aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/SPComboPopupButton.h52
-rw-r--r--Source/SPComboPopupButton.m312
-rw-r--r--Source/SPConstants.h1
-rw-r--r--Source/SPConstants.m1
-rw-r--r--Source/SPCustomQuery.h24
-rw-r--r--Source/SPCustomQuery.m192
-rw-r--r--Source/SPTableStructure.m1
7 files changed, 512 insertions, 71 deletions
diff --git a/Source/SPComboPopupButton.h b/Source/SPComboPopupButton.h
new file mode 100644
index 00000000..f6514e05
--- /dev/null
+++ b/Source/SPComboPopupButton.h
@@ -0,0 +1,52 @@
+//
+// $Id$
+//
+// SPComboPopupButton.h
+// sequel-pro
+//
+// Created by Rowan Beentje (rowan.beent.je) on March 22, 2013
+// Copyright (c) 2013 Rowan Beentje. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface SPComboPopupButton : NSPopUpButton {
+ BOOL menuIsOpen;
+ BOOL shouldDrawNonHighlightState;
+ NSUInteger lineOffset;
+
+ SEL actionSelector;
+ id actionTarget;
+}
+
+@property(readonly, assign) BOOL shouldDrawNonHighlightState;
+@property(readonly, assign) NSUInteger lineOffset;
+
+@end
+
+@interface SPComboPopupButtonCell : NSPopUpButtonCell
+
+@end
diff --git a/Source/SPComboPopupButton.m b/Source/SPComboPopupButton.m
new file mode 100644
index 00000000..9ee71084
--- /dev/null
+++ b/Source/SPComboPopupButton.m
@@ -0,0 +1,312 @@
+//
+// $Id$
+//
+// SPComboPopupButton.m
+// sequel-pro
+//
+// Created by Rowan Beentje (rowan.beent.je) on March 22, 2013
+// Copyright (c) 2013 Rowan Beentje. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPComboPopupButton.h"
+
+#define kSPComboPopupButtonLineOffsetMini 13;
+#define kSPComboPopupButtonLineOffsetSmall 15;
+#define kSPComboPopupButtonLineOffsetRegular 17;
+
+@interface SPComboPopupButton (PrivateAPI)
+
+- (void)_initCustomData;
+
+@end
+
+@implementation SPComboPopupButton
+
+@synthesize shouldDrawNonHighlightState;
+@synthesize lineOffset;
+
+#pragma mark -
+#pragma mark Setup
+
+- (id)initWithCoder:(NSCoder *)decoder
+{
+ if ((self = [super initWithCoder:decoder])) {
+ [self _initCustomData];
+ }
+ return self;
+}
+
+- (id)initWithFrame:(NSRect)frameRect pullsDown:(BOOL)flag
+{
+ if ((self = [super initWithFrame:frameRect pullsDown:flag])) {
+ [self _initCustomData];
+ }
+ return self;
+}
+
+/**
+ * Default to the overridden class. Note that this won't apply to instanced
+ * created in a xib, where the cell class should be selected appropriately.
+ */
++ (Class)cellClass
+{
+ return [SPComboPopupButtonCell class];
+}
+
+#pragma mark -
+#pragma mark Drawing
+
+/**
+ * Draw the control, largely leveraging NSPopupButton drawing but with tweaks
+ * to draw a separator line and different highlights if the dropdown area is
+ * selected.
+ */
+- (void)drawRect:(NSRect)dirtyRect
+{
+ NSRect boundsRect = [self bounds];
+ CGFloat boundingLinePosition = boundsRect.origin.x + boundsRect.size.width - lineOffset - 0.5;
+ CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+ CGFloat heightIndent = ([self isFlipped] ? 4.f : -4.f);
+
+ // Allow the NSPopupButton to draw the majority of the button, with one exception:
+ // if the menu is open, only draw part of the rectangle highlighted.
+ if (menuIsOpen) {
+
+ // Draw the unhighlighted button state in the left-hand part of the button
+ NSRect partialDirtyRect = NSIntersectionRect(dirtyRect, NSMakeRect(boundsRect.origin.x, boundsRect.origin.y, boundingLinePosition - boundsRect.origin.x, boundsRect.size.height));
+ if (!NSIsEmptyRect(partialDirtyRect)) {
+ CGContextSaveGState(context);
+ CGContextClipToRect(context, NSRectToCGRect(partialDirtyRect));
+ shouldDrawNonHighlightState = YES;
+ [super drawRect:partialDirtyRect];
+ shouldDrawNonHighlightState = NO;
+ CGContextRestoreGState(context);
+ }
+
+ // Draw the right-hand side of the button as normal
+ partialDirtyRect = NSIntersectionRect(dirtyRect, NSMakeRect(boundingLinePosition - 0.5, boundsRect.origin.y, boundsRect.origin.x + boundsRect.size.width + 0.5 - boundingLinePosition, boundsRect.size.height));
+ if (!NSIsEmptyRect(partialDirtyRect)) {
+ CGContextSaveGState(context);
+ CGContextClipToRect(context, NSRectToCGRect(partialDirtyRect));
+ [super drawRect:dirtyRect];
+ CGContextRestoreGState(context);
+ }
+ } else {
+ [super drawRect:dirtyRect];
+ }
+
+ // Draw the divider line for the two parts of the button
+ NSColor *lineBaseColor = [[NSColor lightGrayColor] colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]];
+ CGFloat lineColorParts[[lineBaseColor numberOfComponents]];
+ CGColorSpaceRef rgbSpace = CGColorSpaceCreateDeviceRGB();
+ [lineBaseColor getComponents:(CGFloat *)&lineColorParts];
+ CGColorRef lineColor = CGColorCreate(rgbSpace, lineColorParts);
+ CGColorRef lineEdgeColor = CGColorCreateCopyWithAlpha(lineColor, 0.1);
+ CGColorRef gradientColors[] = { lineEdgeColor, lineColor, lineColor, lineEdgeColor };
+ CFArrayRef colorArray = CFArrayCreate(NULL, (const void **)gradientColors, 4, &kCFTypeArrayCallBacks);
+ CGFloat gradientPositions[] = { 0.05, 0.25, 0.75, 0.95 };
+ CGGradientRef lineGradient = CGGradientCreateWithColors(rgbSpace, colorArray, gradientPositions);
+
+ CGContextSaveGState(context);
+ CGContextSetStrokeColor(context, lineColorParts);
+ CGContextAddRect(context, CGRectMake(boundingLinePosition - 0.5, boundsRect.origin.y + heightIndent, 1.f, boundsRect.size.height - abs(2 * heightIndent)));
+ CGContextClip(context);
+ CGContextDrawLinearGradient(context, lineGradient, CGPointMake(boundingLinePosition - 0.5, boundsRect.origin.y + heightIndent), CGPointMake(boundingLinePosition - 0.5, boundsRect.origin.y + boundsRect.size.height - abs(heightIndent)), 0);
+ CGContextRestoreGState(context);
+
+ CGGradientRelease(lineGradient);
+ CFRelease(colorArray);
+ CGColorRelease(lineEdgeColor);
+ CGColorRelease(lineColor);
+ CGColorSpaceRelease(rgbSpace);
+}
+
+#pragma mark -
+#pragma mark Click action overrides
+
+- (void)performClick:(id)sender
+{
+ if (actionSelector && actionTarget) {
+ [self sendAction:actionSelector to:actionTarget];
+ }
+}
+
+- (id)target
+{
+ return actionTarget;
+}
+
+- (void)setTarget:(id)anObject
+{
+ actionTarget = anObject;
+}
+
+- (SEL)action
+{
+ return actionSelector;
+}
+
+- (void)setAction:(SEL)aSelector
+{
+ actionSelector = aSelector;
+}
+
+#pragma mark -
+#pragma mark Menu delegate implementation
+
+- (void)menuWillOpen:(NSMenu *)menu
+{
+ menuIsOpen = YES;
+}
+
+- (void)menuDidClose:(NSMenu *)menu
+{
+ menuIsOpen = NO;
+}
+
+@end
+
+#pragma mark -
+
+@implementation SPComboPopupButton (PrivateAPI)
+
+- (void)_initCustomData
+{
+
+ // Set the line position based on the initial control size
+ switch ([[self cell] controlSize]) {
+ case NSMiniControlSize:
+ lineOffset = kSPComboPopupButtonLineOffsetMini;
+ break;
+ case NSSmallControlSize:
+ lineOffset = kSPComboPopupButtonLineOffsetSmall;
+ break;
+ default:
+ lineOffset = kSPComboPopupButtonLineOffsetRegular;
+ break;
+ }
+
+ // Track when the menu is open via delegate methods
+ menuIsOpen = NO;
+ [[[self cell] menu] setDelegate:self];
+
+ // Move any xib-specified action and target for use as the button target
+ actionSelector = [super action];
+ [super setAction:NULL];
+ actionTarget = [super target];
+ [super setTarget:nil];
+}
+
+@end
+
+#pragma mark -
+
+@interface SPComboPopupButtonCell (PrivateAPI)
+
+- (void)_initCustomData;
+
+@end
+
+@implementation SPComboPopupButtonCell
+
+/**
+ * Indent the title slightly to take account of the additional divider
+ */
+- (NSRect)drawTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView
+{
+ frame.size.width -= 1;
+ return [super drawTitle:title withFrame:frame inView:controlView];
+}
+
+/**
+ * Allow the button to overwrite the draw status as required
+ */
+- (BOOL)isHighlighted
+{
+ if ([(SPComboPopupButton *)[self controlView] shouldDrawNonHighlightState]) {
+ return NO;
+ }
+ return [super isHighlighted];
+}
+
+#pragma mark -
+#pragma mark Custom interaction handling
+
+- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp
+{
+ NSPoint thePoint;
+ NSRect activeRect;
+ CGFloat heightIndent = ([controlView isFlipped] ? 2.f : -2.f);
+ BOOL mouseInButton = YES;
+ BOOL trackAsPerMenuButton = NO;
+
+ // If the event isn't a mouse button event, allow the NSPopUpButtonCell to handle it
+ if ([theEvent type] != NSLeftMouseDown) {
+ trackAsPerMenuButton = YES;
+ }
+
+ // If the view doesn't support line position checks, pass on the event
+ else if (![controlView respondsToSelector:@selector(lineOffset)]) {
+ trackAsPerMenuButton = YES;
+ }
+
+ // If the click is to the right of the line, show the menu
+ else if ([controlView convertPoint:theEvent.locationInWindow fromView:nil].x + [(SPComboPopupButton *)controlView lineOffset] >= [controlView frame].size.width) {
+ trackAsPerMenuButton = YES;
+ }
+
+ if (trackAsPerMenuButton) {
+ return [super trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:untilMouseUp];
+ }
+
+
+ // Custom tracking to be performed - indent the vertical button area slightly
+ activeRect = NSMakeRect(cellFrame.origin.x, cellFrame.origin.y + heightIndent, cellFrame.size.width - [(SPComboPopupButton *)controlView lineOffset] + 1, cellFrame.size.height - fabsf(2 * heightIndent));
+
+ // Continue tracking the mouse while it's down, updating the state as it enters and leaves the cell,
+ // until it is released; if still within the cell, perform a click.
+ while ([theEvent type] != NSLeftMouseUp) {
+ thePoint = [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
+
+ if (NSMouseInRect(thePoint, activeRect, [controlView isFlipped]) != mouseInButton) {
+ mouseInButton = !mouseInButton;
+ [self setHighlighted:mouseInButton];
+ }
+
+ theEvent = [[controlView window] nextEventMatchingMask:(NSLeftMouseUpMask | NSLeftMouseDraggedMask)];
+ }
+
+ // If the mouse is still inside the button area, perform a click action and restore state
+ if (mouseInButton) {
+ if ([controlView respondsToSelector:@selector(performClick:)]) {
+ [(NSControl *)controlView performClick:self];
+ }
+ [self setHighlighted:NO];
+ }
+
+ return YES;
+}
+
+@end
diff --git a/Source/SPConstants.h b/Source/SPConstants.h
index c321d1fa..b353b2dc 100644
--- a/Source/SPConstants.h
+++ b/Source/SPConstants.h
@@ -406,6 +406,7 @@ extern NSString *SPQueryFavorites;
extern NSString *SPQueryFavoriteReplacesContent;
extern NSString *SPQueryHistory;
extern NSString *SPQueryHistoryReplacesContent;
+extern NSString *SPQueryPrimaryControlRunsAll;
extern NSString *SPQuickLookTypes;
extern NSString *SPTableChangedNotification;
extern NSString *SPTableInfoChangedNotification;
diff --git a/Source/SPConstants.m b/Source/SPConstants.m
index 74468d5a..3204b8b8 100644
--- a/Source/SPConstants.m
+++ b/Source/SPConstants.m
@@ -212,6 +212,7 @@ NSString *SPQueryFavorites = @"queryFavorites";
NSString *SPQueryFavoriteReplacesContent = @"QueryFavoriteReplacesContent";
NSString *SPQueryHistory = @"queryHistory";
NSString *SPQueryHistoryReplacesContent = @"QueryHistoryReplacesContent";
+NSString *SPQueryPrimaryControlRunsAll = @"QueryPrimaryControlRunsAll";
NSString *SPQuickLookTypes = @"QuickLookTypes";
NSString *SPTableChangedNotification = @"SPTableSelectionChanged";
NSString *SPTableInfoChangedNotification = @"SPTableInformationChanged";
diff --git a/Source/SPCustomQuery.h b/Source/SPCustomQuery.h
index 982b2059..ffca796b 100644
--- a/Source/SPCustomQuery.h
+++ b/Source/SPCustomQuery.h
@@ -95,11 +95,16 @@
IBOutlet id affectedRowsText;
IBOutlet id valueSheet;
IBOutlet id valueTextField;
- IBOutlet id runSelectionButton;
+
+ // Hooks for old layouts using just the Run All button
IBOutlet id runAllButton;
- IBOutlet NSMenuItem *runSelectionMenuItem;
- IBOutlet NSMenuItem *runAllMenuItem;
+ // Hooks for layouts using the new single button with interchangeable actions
+ IBOutlet id runPrimaryActionButton;
+ IBOutlet id runPrimaryActionButtonAsSelection;
+ IBOutlet NSMenuItem *runPrimaryActionMenuItem;
+ IBOutlet NSMenuItem *runSecondaryActionMenuItem;
+
IBOutlet NSMenuItem *shiftLeftMenuItem;
IBOutlet NSMenuItem *shiftRightMenuItem;
IBOutlet NSMenuItem *completionListMenuItem;
@@ -136,8 +141,8 @@
NSString *usedQuery;
NSRange currentQueryRange;
NSArray *currentQueryRanges;
+ BOOL currentQueryBeforeCaret;
- BOOL selectionButtonCanBeEnabled;
NSString *mySQLversion;
NSTableColumn *sortColumn;
@@ -191,13 +196,16 @@
@property (assign) SPTablesList* tablesListInstance;
@property (assign) SPTextView *textView;
@property (assign) SPCopyTable *customQueryView;
-@property (assign) NSButton* runAllButton;
@property (assign) id affectedRowsText;
#endif
-@property(assign) BOOL textViewWasChanged;
+@property (assign) NSButton* runAllButton;
+@property (assign) BOOL textViewWasChanged;
// IBAction methods
+- (IBAction)runPrimaryQueryAction:(id)sender;
+- (IBAction)runSecondaryQueryAction:(id)sender;
+- (IBAction)switchDefaultQueryAction:(id)sender;
- (IBAction)runAllQueries:(id)sender;
- (IBAction)runSelectedQueries:(id)sender;
- (IBAction)chooseQueryFavorite:(id)sender;
@@ -230,6 +238,10 @@
- (NSRange)queryTextRangeForQuery:(NSInteger)anIndex startPosition:(NSUInteger)position;
- (void)updateStatusInterfaceWithDetails:(NSDictionary *)errorDetails;
+// Interface setup
+- (void)updateQueryInteractionInterface;
+- (void)updateContextualRunInterface;
+
// Query load actions
- (void)initQueryLoadTimer;
- (void)clearQueryLoadTimer;
diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m
index 38224eec..b5a99a37 100644
--- a/Source/SPCustomQuery.m
+++ b/Source/SPCustomQuery.m
@@ -58,6 +58,7 @@
#import "SPTextView.h"
#import "RegexKitLite.h"
#import "SPThreadAdditions.h"
+#import "SPConstants.h"
#ifndef SP_REFACTOR /* headers */
#import "SPAppController.h"
#import "SPBundleHTMLOutputController.h"
@@ -79,16 +80,50 @@
#ifdef SP_REFACTOR
@synthesize textView;
@synthesize customQueryView;
-@synthesize runAllButton;
@synthesize tableDocumentInstance;
@synthesize tablesListInstance;
@synthesize affectedRowsText;
#endif
+@synthesize runAllButton;
@synthesize textViewWasChanged;
#pragma mark IBAction methods
+/**
+ * Run the primary query task, as per the user preference
+ */
+- (IBAction)runPrimaryQueryAction:(id)sender
+{
+ if ([prefs boolForKey:SPQueryPrimaryControlRunsAll]) {
+ [self runAllQueries:sender];
+ } else {
+ [self runSelectedQueries:sender];
+ }
+}
+
+/**
+ * Run the secondary query task, as per the user preference
+ */
+- (IBAction)runSecondaryQueryAction:(id)sender
+{
+ if ([prefs boolForKey:SPQueryPrimaryControlRunsAll]) {
+ [self runSelectedQueries:sender];
+ } else {
+ [self runAllQueries:sender];
+ }
+}
+
+/**
+ * Swap the primary and secondary query run actions
+ */
+- (IBAction)switchDefaultQueryAction:(id)sender
+{
+ BOOL newValue = ![prefs boolForKey:SPQueryPrimaryControlRunsAll];
+ [prefs setBool:newValue forKey:SPQueryPrimaryControlRunsAll];
+ [self updateQueryInteractionInterface];
+}
+
/*
* Split all the queries in the text view, split them into individual queries,
* and run sequentially.
@@ -1355,6 +1390,67 @@
}
#pragma mark -
+#pragma mark Interface setup
+
+/**
+ * Update the Run Selection/Query/All button and menu item state according
+ * to the user preferences.
+ */
+- (void)updateQueryInteractionInterface
+{
+
+ // By default, the interface uses Run Query/Run Selection as the primary interface,
+ // but the user can switch this.
+ BOOL primaryActionIsRunAll = [prefs boolForKey:SPQueryPrimaryControlRunsAll];
+
+ // Update the links as appropriate
+ if (primaryActionIsRunAll) {
+ runPrimaryActionButtonAsSelection = nil;
+ [runPrimaryActionButton setTitle:NSLocalizedString(@"Run All", @"run all button")];
+ [runPrimaryActionMenuItem setTitle:NSLocalizedString(@"Run All Queries", @"Run All menu item title")];
+ } else {
+ runPrimaryActionButtonAsSelection = runPrimaryActionButton;
+ [runSecondaryActionMenuItem setTitle:NSLocalizedString(@"Run All Queries", @"Run All menu item title")];
+ }
+
+ // Update the Run Current/Previous/Selection menu item (and button if appropriate)
+ [self updateContextualRunInterface];
+}
+
+/**
+ * Update the selection-sensitive "Run Current" / "Run Previous" / "Run Selection"
+ * button and menu items based on the current interface state
+ */
+- (void)updateContextualRunInterface
+{
+ NSMenuItem *runSelectionMenuItem;
+
+ // Determine the menu item to change
+ if (runPrimaryActionButtonAsSelection) {
+ runSelectionMenuItem = runPrimaryActionMenuItem;
+ } else {
+ runSelectionMenuItem = runSecondaryActionMenuItem;
+ }
+
+ // If the current selection is a single caret position, update the button based on
+ // whether the caret is inside a valid query.
+ if (![textView selectedRange].length) {
+ if (currentQueryBeforeCaret) {
+ [runPrimaryActionButtonAsSelection setTitle:NSLocalizedString(@"Run Previous", @"Title of button to run query just before text caret in custom query view")];
+ [runSelectionMenuItem setTitle:NSLocalizedString(@"Run Previous Query", @"Title of action menu item to run query just before text caret in custom query view")];
+ } else {
+ [runPrimaryActionButtonAsSelection setTitle:NSLocalizedString(@"Run Current", @"Title of button to run current query in custom query view")];
+ [runSelectionMenuItem setTitle:NSLocalizedString(@"Run Current Query", @"Title of action menu item to run current query in custom query view")];
+ }
+
+ // Otherwise, reflect the active selection
+ } else {
+ [runPrimaryActionButtonAsSelection setTitle:NSLocalizedString(@"Run Selection", @"Title of button to run selected text in custom query view")];
+ [runSelectionMenuItem setTitle:NSLocalizedString(@"Run Selected Text", @"Title of action menu item to run selected text in custom query view")];
+ }
+}
+
+#pragma mark -
#pragma mark Table load actions
/**
@@ -1520,9 +1616,6 @@
// Populate query favorites
[self queryFavoritesHaveBeenUpdated:nil];
#endif
-
- // Disable runSelectionMenuItem in the gear menu
- [runSelectionMenuItem setEnabled:NO];
}
/**
@@ -2594,7 +2687,7 @@
if (aTextView == textView) {
if ([aTextView methodForSelector:aSelector] == [aTextView methodForSelector:@selector(insertNewline:)] &&
[[[NSApp currentEvent] characters] isEqualToString:@"\003"]) {
- [self runAllQueries:self];
+ [self runPrimaryQueryAction:self];
return YES;
}
@@ -2637,69 +2730,37 @@
// Ensure that the notification is from the custom query text view
if ( [aNotification object] != textView ) return;
- BOOL isLookBehind = YES;
NSRange currentSelection = [textView selectedRange];
NSUInteger caretPosition = currentSelection.location;
- NSRange qRange = [self queryRangeAtPosition:caretPosition lookBehind:&isLookBehind];
+ // Detect the current query range, allowing the search to occur if the caret is after
+ // a semicolon
+ currentQueryBeforeCaret = YES;
+ currentQueryRange = [self queryRangeAtPosition:caretPosition lookBehind:&currentQueryBeforeCaret];
- if(qRange.length)
- currentQueryRange = qRange;
- else
- currentQueryRange = NSMakeRange(0, 0);
-
- [textView setQueryRange:qRange];
+ [textView setQueryRange:currentQueryRange];
[textView setNeedsDisplayInRect:[textView bounds]];
- // disable "Comment Current Query" menu item if no current query is selectable
- [commentCurrentQueryMenuItem setEnabled:(currentQueryRange.length) ? YES : NO];
-
- // If no text is selected, disable the button and action menu.
- if ( caretPosition == NSNotFound ) {
- selectionButtonCanBeEnabled = NO;
- [runSelectionButton setEnabled:NO];
- [runSelectionMenuItem setEnabled:NO];
- return;
+ // If a query range is selected, update the current query range and menu actions
+ if (currentQueryRange.length) {
+ [commentCurrentQueryMenuItem setEnabled:YES];
+ } else {
+ currentQueryRange = NSMakeRange(0, 0);
+ [commentCurrentQueryMenuItem setEnabled:NO];
}
- // If the current selection is a single caret position, update the button based on
- // whether the caret is inside a valid query.
- if (!currentSelection.length) {
- [runSelectionButton setTitle:NSLocalizedString(@"Run Current", @"Title of button to run current query in custom query view")];
- [runSelectionMenuItem setTitle:NSLocalizedString(@"Run Current Query", @"Title of action menu item to run current query in custom query view")];
-
- // If a valid query is present at the cursor position, enable the button
- if (qRange.length) {
- if (isLookBehind) {
- [runSelectionButton setTitle:NSLocalizedString(@"Run Previous", @"Title of button to run query just before text caret in custom query view")];
- [runSelectionMenuItem setTitle:NSLocalizedString(@"Run Previous Query", @"Title of action menu item to run query just before text caret in custom query view")];
- }
- selectionButtonCanBeEnabled = YES;
- if (![tableDocumentInstance isWorking]) {
- [runSelectionButton setEnabled:YES];
- [runSelectionMenuItem setEnabled:YES];
- }
- } else {
- selectionButtonCanBeEnabled = NO;
- [runSelectionButton setEnabled:NO];
- [runSelectionMenuItem setEnabled:NO];
- }
- [commentLineOrSelectionMenuItem setTitle:NSLocalizedString(@"Comment Line", @"Title of action menu item to comment line")];
-
- // For selection ranges, enable the button.
- } else {
- selectionButtonCanBeEnabled = YES;
- [runSelectionButton setTitle:NSLocalizedString(@"Run Selection", @"Title of button to run selected text in custom query view")];
- [runSelectionMenuItem setTitle:NSLocalizedString(@"Run Selected Text", @"Title of action menu item to run selected text in custom query view")];
+ // Vary the comment/line selection menu item according to whether a section is present
+ if (currentSelection.length) {
[commentLineOrSelectionMenuItem setTitle:NSLocalizedString(@"Comment Selection", @"Title of action menu item to comment selection")];
- if (![tableDocumentInstance isWorking]) {
- [runSelectionButton setEnabled:YES];
- [runSelectionMenuItem setEnabled:YES];
- }
+ } else {
+ [commentLineOrSelectionMenuItem setTitle:NSLocalizedString(@"Comment Line", @"Title of action menu item to comment line")];
}
- if(!historyItemWasJustInserted)
+ if (!historyItemWasJustInserted)
currentHistoryOffsetIndex = -1;
+
+ // Update the text of the contextual run current/previous/selection button and menu item
+ [self updateContextualRunInterface];
}
#pragma mark -
@@ -3391,10 +3452,10 @@
#endif
tableRowsSelectable = NO;
- [runSelectionButton setEnabled:NO];
- [runSelectionMenuItem setEnabled:NO];
[runAllButton setEnabled:NO];
- [runAllMenuItem setEnabled:NO];
+ [runPrimaryActionButton setEnabled:NO];
+ [runPrimaryActionMenuItem setEnabled:NO];
+ [runSecondaryActionMenuItem setEnabled:NO];
}
/**
@@ -3410,13 +3471,11 @@
return;
#endif
- if (selectionButtonCanBeEnabled) {
- [runSelectionButton setEnabled:YES];
- [runSelectionMenuItem setEnabled:YES];
- }
tableRowsSelectable = YES;
[runAllButton setEnabled:YES];
- [runAllMenuItem setEnabled:YES];
+ [runPrimaryActionButton setEnabled:YES];
+ [runPrimaryActionMenuItem setEnabled:YES];
+ [runSecondaryActionMenuItem setEnabled:YES];
}
#pragma mark -
@@ -3656,7 +3715,6 @@
sortField = nil;
isDesc = NO;
sortColumn = nil;
- selectionButtonCanBeEnabled = NO;
isFieldEditable = NO;
cqColumnDefinition = nil;
favoritesManager = nil;
@@ -3692,6 +3750,9 @@
currentHistoryOffsetIndex = -1;
historyItemWasJustInserted = NO;
+ currentQueryRange = NSMakeRange(0, 0);
+ currentQueryBeforeCaret = NO;
+ runPrimaryActionButtonAsSelection = nil;
queryLoadTimer = nil;
@@ -3866,6 +3927,7 @@
{
[customQueryView setFieldEditorSelectedRange:NSMakeRange(0,0)];
+ [self updateQueryInteractionInterface];
// Set pre-defined menu tags
[queryFavoritesSaveAsMenuItem setTag:SP_SAVE_SELECTION_FAVORTITE_MENUITEM_TAG];
diff --git a/Source/SPTableStructure.m b/Source/SPTableStructure.m
index 11d6aeac..fcbc7d13 100644
--- a/Source/SPTableStructure.m
+++ b/Source/SPTableStructure.m
@@ -46,6 +46,7 @@
#import "SPTableFieldValidation.h"
#import "SPTableStructureLoading.h"
#import "SPThreadAdditions.h"
+#import "SPServerSupport.h"
#import <SPMySQL/SPMySQL.h>