From cca030a98637bec8e8a731efb7ad15b3f458b115 Mon Sep 17 00:00:00 2001 From: rowanbeentje Date: Sun, 31 Mar 2013 23:05:36 +0000 Subject: Combine the "Run All" and "Run Current/Previous/Selection" buttons into a single button with dropdown menu with ability to change the default action: - Create a new SPComboPopupButton class; this subclasses NSPopupButton to retain the ability to show the popup menu, but only when the right-hand side of the button is pressed, allowing the rest of the button to perform the click action - Combine the previous two "Run" buttons on the Custom Query view into a new SPComboPopupButton - Move the Run menu items from the gear menu into the Run button popup menu so they can be discovered more easily (and the shortcuts seen more easily) - Add a menu item to switch the button's default action, which also swaps all associated shortcuts - Clean up associated logic This implements Issue #1569 --- Source/SPComboPopupButton.h | 52 ++++++++ Source/SPComboPopupButton.m | 312 ++++++++++++++++++++++++++++++++++++++++++++ Source/SPConstants.h | 1 + Source/SPConstants.m | 1 + Source/SPCustomQuery.h | 24 +++- Source/SPCustomQuery.m | 193 ++++++++++++++++++--------- 6 files changed, 512 insertions(+), 71 deletions(-) create mode 100644 Source/SPComboPopupButton.h create mode 100644 Source/SPComboPopupButton.m (limited to 'Source') diff --git a/Source/SPComboPopupButton.h b/Source/SPComboPopupButton.h new file mode 100644 index 00000000..74b003cf --- /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 + +#import + + +@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..76280dac --- /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 + +#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, 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 cad10d95..a5683cbf 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 896889f1..4ce76b57 100644 --- a/Source/SPCustomQuery.h +++ b/Source/SPCustomQuery.h @@ -101,11 +101,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; @@ -144,8 +149,8 @@ NSString *usedQuery; NSRange currentQueryRange; NSArray *currentQueryRanges; + BOOL currentQueryBeforeCaret; - BOOL selectionButtonCanBeEnabled; NSString *mySQLversion; NSTableColumn *sortColumn; @@ -199,13 +204,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; @@ -238,6 +246,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 08b5838c..26f66831 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_CODA /* headers */ #import "SPAppController.h" #import "SPBundleHTMLOutputController.h" @@ -79,16 +80,50 @@ #ifdef SP_CODA @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. @@ -1340,6 +1375,68 @@ #endif } +#pragma mark - +#pragma mark Interface setup + +/** + * Update the Run Selection/Query/All button and menu item state according + * to the user preferences. + */ +- (void)updateQueryInteractionInterface +{ + NSString *runAllTitle = NSLocalizedString(@"Run All Queries", @"Run All button and menu item title"); + + // 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:runAllTitle]; + [runPrimaryActionMenuItem setTitle:runAllTitle]; + } else { + runPrimaryActionButtonAsSelection = runPrimaryActionButton; + [runSecondaryActionMenuItem setTitle:runAllTitle]; + } + + // 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 @@ -1506,9 +1603,6 @@ // Populate query favorites [self queryFavoritesHaveBeenUpdated:nil]; #endif - - // Disable runSelectionMenuItem in the gear menu - [runSelectionMenuItem setEnabled:NO]; } /** @@ -2568,7 +2662,7 @@ if (aTextView == textView) { if ([aTextView methodForSelector:aSelector] == [aTextView methodForSelector:@selector(insertNewline:)] && [[[NSApp currentEvent] characters] isEqualToString:@"\003"]) { - [self runSelectedQueries:self]; + [self runPrimaryQueryAction:self]; return YES; } @@ -2611,69 +2705,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:¤tQueryBeforeCaret]; - 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 - @@ -3383,10 +3445,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]; } /** @@ -3402,13 +3464,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 - @@ -3655,7 +3715,6 @@ sortField = nil; isDesc = NO; sortColumn = nil; - selectionButtonCanBeEnabled = NO; isFieldEditable = NO; cqColumnDefinition = nil; favoritesManager = nil; @@ -3691,6 +3750,9 @@ currentHistoryOffsetIndex = -1; historyItemWasJustInserted = NO; + currentQueryRange = NSMakeRange(0, 0); + currentQueryBeforeCaret = NO; + runPrimaryActionButtonAsSelection = nil; queryLoadTimer = nil; @@ -3874,6 +3936,7 @@ { [customQueryView setFieldEditorSelectedRange:NSMakeRange(0,0)]; + [self updateQueryInteractionInterface]; #ifndef SP_CODA // Set pre-defined menu tags -- cgit v1.2.3