aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorstuconnolly <stuart02@gmail.com>2010-12-08 19:03:47 +0000
committerstuconnolly <stuart02@gmail.com>2010-12-08 19:03:47 +0000
commit61e398816badc49b301a6ae70c3697d581258cfb (patch)
treecca1e18f88c42556b4a5e48c1e685cb2b6574b78 /Source
parent3fccc9c751cded1360aa22796ed3c6d700fd04c1 (diff)
parent5b88ac6a6d0c02b1b51f295cf79e84b61c1f1bd5 (diff)
downloadsequelpro-61e398816badc49b301a6ae70c3697d581258cfb.tar.gz
sequelpro-61e398816badc49b301a6ae70c3697d581258cfb.tar.bz2
sequelpro-61e398816badc49b301a6ae70c3697d581258cfb.zip
Bring outline view branch up to date with trunk (r2976:2988).
Diffstat (limited to 'Source')
-rw-r--r--Source/SPAppController.m148
-rw-r--r--Source/SPBundleCommandTextView.h3
-rw-r--r--Source/SPBundleCommandTextView.m87
-rw-r--r--Source/SPBundleEditorController.h3
-rw-r--r--Source/SPBundleEditorController.m68
-rw-r--r--Source/SPConstants.h24
-rw-r--r--Source/SPConstants.m30
-rw-r--r--Source/SPCopyTable.m432
-rw-r--r--Source/SPCustomQuery.h1
-rw-r--r--Source/SPCustomQuery.m8
-rw-r--r--Source/SPDatabaseDocument.m22
-rw-r--r--Source/SPNarrowDownCompletion.m34
-rw-r--r--Source/SPStringAdditions.m92
-rw-r--r--Source/SPTableContent.h1
-rw-r--r--Source/SPTableContent.m8
-rw-r--r--Source/SPTableStructure.m5
-rw-r--r--Source/SPTextViewAdditions.m48
17 files changed, 727 insertions, 287 deletions
diff --git a/Source/SPAppController.m b/Source/SPAppController.m
index c398b219..f51cfc13 100644
--- a/Source/SPAppController.m
+++ b/Source/SPAppController.m
@@ -640,7 +640,7 @@
// Try to find the SPDatabaseDocument which sent the the url scheme command
// For speed check the front most first otherwise iterate through all
- if(passedProcessID) {
+ if(passedProcessID && [passedProcessID length]) {
if([activeProcessID isEqualToString:passedProcessID]) {
processDocument = [[[self frontDocumentWindow] delegate] selectedTableDocument];
} else {
@@ -691,18 +691,26 @@
return;
}
- // If command failed notify the file handle hand shake mechanism
- NSString *out = @"1";
- [out writeToFile:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultStatusPathHeader, passedProcessID]
- atomically:YES
- encoding:NSUTF8StringEncoding
- error:nil];
- out = @"Scheme Error";
- [out writeToFile:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultPathHeader, passedProcessID]
- atomically:YES
- encoding:NSUTF8StringEncoding
- error:nil];
+ if(processDocument != nil) {
+ // If command failed notify the file handle hand shake mechanism
+ NSString *out = @"1";
+ [out writeToFile:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultStatusPathHeader, passedProcessID]
+ atomically:YES
+ encoding:NSUTF8StringEncoding
+ error:nil];
+ out = @"Scheme Error";
+ [out writeToFile:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultPathHeader, passedProcessID]
+ atomically:YES
+ encoding:NSUTF8StringEncoding
+ error:nil];
+ }
+ if(passedProcessID == nil || ![passedProcessID length]) {
+ SPBeginAlertSheet(NSLocalizedString(@"sequelpro URL Scheme Error", @"sequelpro url Scheme Error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil,
+ [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [command description], NSLocalizedString(@"An error occur while executing a scheme command. If the scheme command was invoked by a Bundle command, it could be that the command still runs. You can try to terminate it by pressing ⌘+. or via the Activities pane.", @"an error occur while executing a scheme command. if the scheme command was invoked by a bundle command, it could be that the command still runs. you can try to terminate it by pressing ⌘+. or via the activities pane.")]);
+ } else {
+ NSBeep();
+ }
if(processDocument)
NSLog(@"process doc ID: %@\n%@", [processDocument processID], [processDocument tabTitleForTooltip]);
@@ -753,40 +761,18 @@
NSString *inputAction = @"";
NSString *inputFallBackAction = @"";
NSError *err = nil;
- NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, [NSString stringWithNewUUID]];
+ NSString *uuid = [NSString stringWithNewUUID];
+ NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, uuid];
[[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil];
- if([cmdData objectForKey:SPBundleFileInputSourceKey])
- inputAction = [[cmdData objectForKey:SPBundleFileInputSourceKey] lowercaseString];
- if([cmdData objectForKey:SPBundleFileInputSourceFallBackKey])
- inputFallBackAction = [[cmdData objectForKey:SPBundleFileInputSourceFallBackKey] lowercaseString];
-
NSMutableDictionary *env = [NSMutableDictionary dictionary];
- [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:@"SP_BUNDLE_PATH"];
- [env setObject:bundleInputFilePath forKey:@"SP_BUNDLE_INPUT_FILE"];
+ [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:SPBundleShellVariableBundlePath];
+ [env setObject:bundleInputFilePath forKey:SPBundleShellVariableInputFilePath];
+ [env setObject:SPBundleScopeGeneral forKey:SPBundleShellVariableScope];
- NSError *inputFileError = nil;
NSString *input = @"";
- if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsTab]) {
- input = [self rowsAsTabStringWithHeaders:YES onlySelectedRows:YES];
- }
- else if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsCsv]) {
- input = [self rowsAsCsvStringWithHeaders:YES onlySelectedRows:YES];
- }
- else if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsSqlInsert]) {
- input = [self rowsAsSqlInsertsOnlySelectedRows:YES];
- }
- else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsTab]) {
- input = [self rowsAsTabStringWithHeaders:YES onlySelectedRows:NO];
- }
- else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsCsv]) {
- input = [self rowsAsCsvStringWithHeaders:YES onlySelectedRows:NO];
- }
- else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsSqlInsert]) {
- input = [self rowsAsSqlInsertsOnlySelectedRows:NO];
- }
-
+ NSError *inputFileError = nil;
if(input == nil) input = @"";
[input writeToFile:bundleInputFilePath
atomically:YES
@@ -795,7 +781,7 @@
if(inputFileError != nil) {
NSString *errorMessage = [inputFileError localizedDescription];
- SPBeginAlertSheet(NSLocalizedString(@"Bundle Error", @"bundle error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Bundle Error", @"bundle error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [self window], self, nil, nil,
[NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage]);
if (cmdData) [cmdData release];
return;
@@ -807,15 +793,53 @@
contextInfo:[NSDictionary dictionaryWithObjectsAndKeys:
([cmdData objectForKey:SPBundleFileNameKey])?:@"-", @"name",
NSLocalizedString(@"General", @"general menu item label"), @"scope",
+ uuid, SPBundleFileInternalexecutionUUID,
nil]
error:&err];
[[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil];
+ NSString *action = [[cmdData objectForKey:SPBundleFileOutputActionKey] lowercaseString];
+
+ // Redirect due exit code
+ if(err != nil) {
+ if([err code] == SPBundleRedirectActionNone) {
+ action = SPBundleOutputActionNone;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionReplaceSection) {
+ action = SPBundleOutputActionReplaceSelection;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionReplaceContent) {
+ action = SPBundleOutputActionReplaceContent;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionInsertAsText) {
+ action = SPBundleOutputActionInsertAsText;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionInsertAsSnippet) {
+ action = SPBundleOutputActionInsertAsSnippet;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionShowAsHTML) {
+ action = SPBundleOutputActionShowAsHTML;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionShowAsTextTooltip) {
+ action = SPBundleOutputActionShowAsTextTooltip;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionShowAsHTMLTooltip) {
+ action = SPBundleOutputActionShowAsHTMLTooltip;
+ err = nil;
+ }
+ }
+
if(err == nil && output) {
if([cmdData objectForKey:SPBundleFileOutputActionKey] && [[cmdData objectForKey:SPBundleFileOutputActionKey] length]
&& ![[cmdData objectForKey:SPBundleFileOutputActionKey] isEqualToString:SPBundleOutputActionNone]) {
- NSString *action = [[cmdData objectForKey:SPBundleFileOutputActionKey] lowercaseString];
NSPoint pos = [NSEvent mouseLocation];
pos.y -= 16;
@@ -1302,7 +1326,9 @@
if([cmdData objectForKey:SPBundleFileCategoryKey] && [[cmdData objectForKey:SPBundleFileCategoryKey] length])
[aDict setObject:[cmdData objectForKey:SPBundleFileCategoryKey] forKey:SPBundleFileCategoryKey];
- [aDict setObject:[cmdData objectForKey:SPBundleFileKeyEquivalentKey] forKey:@"key"];
+ if([cmdData objectForKey:SPBundleFileKeyEquivalentKey] && [[cmdData objectForKey:SPBundleFileKeyEquivalentKey] length])
+ [aDict setObject:[cmdData objectForKey:SPBundleFileKeyEquivalentKey] forKey:@"key"];
+
for(NSString* scope in scopes)
[[bundleItems objectForKey:scope] addObject:aDict];
}
@@ -1409,7 +1435,7 @@
[mItem setTag:1000000 + i++];
[mItem setRepresentedObject:[NSDictionary dictionaryWithObjectsAndKeys:
scope, @"scope",
- [item objectForKey:@"key"], @"key", nil]];
+ ([item objectForKey:@"key"])?:@"", @"key", nil]];
if([item objectForKey:SPBundleFileCategoryKey]) {
[[categoryMenus objectAtIndex:[bundleCategories indexOfObject:[item objectForKey:SPBundleFileCategoryKey]]] addItem:mItem];
@@ -1431,16 +1457,42 @@
- (IBAction)bundleCommandDispatcher:(id)sender
{
- BOOL checkForKeyEquivalents = ([[NSApp currentEvent] type] == NSKeyDown) ? YES : NO;
+ NSEvent *event = [NSApp currentEvent];
+ BOOL checkForKeyEquivalents = ([event type] == NSKeyDown) ? YES : NO;
+
+ id firstResponder = [[NSApp mainWindow] firstResponder];
NSString *scope = [[sender representedObject] objectForKey:@"scope"];
NSString *keyEqKey = nil;
NSMutableArray *assignedKeyEquivalents = nil;
if(checkForKeyEquivalents) {
+
+ // Get the current scope in order to find out which command with a specific key
+ // should run
+ if([firstResponder respondsToSelector:@selector(executeBundleItemForInputField:)])
+ scope = SPBundleScopeInputField;
+ else if([firstResponder respondsToSelector:@selector(executeBundleItemForDataTable:)])
+ scope = SPBundleScopeDataTable;
+ else
+ scope = SPBundleScopeGeneral;
+
keyEqKey = [[sender representedObject] objectForKey:@"key"];
+
assignedKeyEquivalents = [NSMutableArray array];
[assignedKeyEquivalents setArray:[[bundleKeyEquivalents objectForKey:scope] objectForKey:keyEqKey]];
+ // Fall back to general scope and check for key
+ if(![assignedKeyEquivalents count]) {
+ scope = SPBundleScopeGeneral;
+ [assignedKeyEquivalents setArray:[[bundleKeyEquivalents objectForKey:scope] objectForKey:keyEqKey]];
+ }
+ // Nothing found thus bail
+ if(![assignedKeyEquivalents count]) {
+ NSBeep();
+ return;
+ }
+
+ // Sort if more than one found
if([assignedKeyEquivalents count] > 1) {
NSSortDescriptor *aSortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES selector:@selector(caseInsensitiveCompare:)] autorelease];
NSArray *sorted = [assignedKeyEquivalents sortedArrayUsingDescriptors:[NSArray arrayWithObject:aSortDescriptor]];
@@ -1448,8 +1500,6 @@
}
}
- id firstResponder = [[NSApp mainWindow] firstResponder];
-
if([scope isEqualToString:SPBundleScopeInputField] && [firstResponder respondsToSelector:@selector(executeBundleItemForInputField:)]) {
if(checkForKeyEquivalents && [assignedKeyEquivalents count]) {
NSInteger idx = 0;
@@ -1489,7 +1539,7 @@
}
}
else if([scope isEqualToString:SPBundleScopeGeneral]) {
- if(checkForKeyEquivalents && [assignedKeyEquivalents objectForKey:keyEqKey]) {
+ if(checkForKeyEquivalents && [assignedKeyEquivalents count]) {
NSInteger idx = 0;
if([assignedKeyEquivalents count] > 1)
idx = [SPChooseMenuItemDialog withItems:assignedKeyEquivalents atPosition:[NSEvent mouseLocation]];
@@ -1500,7 +1550,7 @@
NSMenuItem *aMenuItem = [[[NSMenuItem alloc] init] autorelease];
[aMenuItem setTag:0];
[aMenuItem setToolTip:[eq objectForKey:@"path"]];
- [[[NSApp mainWindow] firstResponder] executeBundleItemForApp:aMenuItem];
+ [self executeBundleItemForApp:aMenuItem];
}
}
} else {
diff --git a/Source/SPBundleCommandTextView.h b/Source/SPBundleCommandTextView.h
index 78e6a02a..119121da 100644
--- a/Source/SPBundleCommandTextView.h
+++ b/Source/SPBundleCommandTextView.h
@@ -38,10 +38,11 @@
- (NSUInteger)characterIndexOfPoint:(NSPoint)aPoint;
- (void)insertFileContentOfFile:(NSString *)aPath;
- (void)saveChangedFontInUserDefaults;
-- (void) setTabStops;
+- (void)setTabStops;
- (BOOL)shiftSelectionRight;
- (BOOL)shiftSelectionLeft;
- (void)commentOut;
+- (BOOL)wrapSelectionWithPrefix:(unichar)prefix;
@end
diff --git a/Source/SPBundleCommandTextView.m b/Source/SPBundleCommandTextView.m
index d5a649bb..8a5bf620 100644
--- a/Source/SPBundleCommandTextView.m
+++ b/Source/SPBundleCommandTextView.m
@@ -337,7 +337,7 @@
[super cut:sender];
}
-- (void) setTabStops
+- (void)setTabStops
{
NSFont *tvFont = [self font];
NSInteger i;
@@ -395,22 +395,86 @@
[paragraphStyle release];
}
+/**
+ * If the textview has a selection, wrap it with the supplied prefix and suffix strings;
+ * return whether or not any wrap was performed.
+ */
+- (BOOL)wrapSelectionWithPrefix:(unichar)prefix
+{
+
+ NSRange currentRange = [self selectedRange];
+
+ // Only proceed if a selection is active
+ if (currentRange.length == 0 || ![self isEditable])
+ return NO;
+
+ NSString *matchingCharacter;
+ NSString *prefixStr = nil;
+
+ // Set matchingCharacter due to prefix.
+ switch (prefix)
+ {
+ case '(':
+ matchingCharacter = @")";
+ break;
+ case '"':
+ matchingCharacter = @"\"";
+ break;
+ case '`':
+ matchingCharacter = @"`";
+ break;
+ case '\'':
+ matchingCharacter = @"'";
+ break;
+ case '{':
+ matchingCharacter = @"}";
+ break;
+ case '[':
+ matchingCharacter = @"]";
+ break;
+ case 0x201c:
+ prefixStr = @"“";
+ matchingCharacter = @"”";
+ break;
+ case 0x2018:
+ prefixStr = @"‘";
+ matchingCharacter = @"’";
+ break;
+ default:
+ return NO;
+ }
+
+ NSString *selString = [[self string] substringWithRange:currentRange];
+ NSString *replaceString;
+ if(prefixStr != nil)
+ replaceString = [NSString stringWithFormat:@"%@%@%@", prefixStr, selString, matchingCharacter];
+ else
+ replaceString = [NSString stringWithFormat:@"%c%@%@", prefix, selString, matchingCharacter];
+
+ [self breakUndoCoalescing];
+
+ // Replace the current selection with the selected string wrapped in prefix and suffix
+ [self insertText:replaceString];
+
+ // Re-select original selection
+ NSRange innerSelectionRange = NSMakeRange(currentRange.location+1, [selString length]);
+ [self setSelectedRange:innerSelectionRange];
+
+ return YES;
+}
+
- (void)keyDown:(NSEvent *)theEvent
{
long allFlags = (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask);
- // Check if user pressed ⌥ to allow composing of accented characters.
- // e.g. for US keyboard "⌥u a" to insert ä
- // or for non-US keyboards to allow to enter dead keys
- // e.g. for German keyboard ` is a dead key, press space to enter `
- if (([theEvent modifierFlags] & allFlags) == NSAlternateKeyMask || [[theEvent characters] length] == 0)
- {
+ NSString *characters = [theEvent characters];
+ NSString *charactersIgnMod = [theEvent charactersIgnoringModifiers];
+ if(![characters length]) {
[super keyDown: theEvent];
return;
}
-
- NSString *charactersIgnMod = [theEvent charactersIgnoringModifiers];
+ unichar insertedCharacter = [characters characterAtIndex:0];
long curFlags = ([theEvent modifierFlags] & allFlags);
if(curFlags & NSCommandKeyMask) {
@@ -452,6 +516,11 @@
[[self delegate] setDoGroupDueToChars];
}
+ // Check to see whether several characters are selected, and if so, wrap them with
+ // the auto-paired characters. This returns false if the selection has zero length.
+ if ([self wrapSelectionWithPrefix:insertedCharacter])
+ return;
+
[super keyDown: theEvent];
}
diff --git a/Source/SPBundleEditorController.h b/Source/SPBundleEditorController.h
index 7cc36de4..d586e5bc 100644
--- a/Source/SPBundleEditorController.h
+++ b/Source/SPBundleEditorController.h
@@ -106,6 +106,8 @@
BOOL selectionChanged;
NSUndoManager *esUndoManager;
+ NSArray *shellVariableSuggestions;
+
}
- (IBAction)inputPopupButtonChanged:(id)sender;
@@ -123,6 +125,7 @@
- (IBAction)saveAndCloseWindow:(id)sender;
- (IBAction)reloadBundles:(id)sender;
- (IBAction)metaButtonChanged:(id)sender;
+- (IBAction)performClose:(id)sender;
- (BOOL)saveBundle:(NSDictionary*)bundle atPath:(NSString*)aPath;
- (BOOL)cancelRowEditing;
diff --git a/Source/SPBundleEditorController.m b/Source/SPBundleEditorController.m
index 2eb58edc..4091e606 100644
--- a/Source/SPBundleEditorController.m
+++ b/Source/SPBundleEditorController.m
@@ -95,6 +95,8 @@
[triggerGeneralArray release];
[withBlobDataTableArray release];
+ [shellVariableSuggestions release];
+
if(touchedBundleArray) [touchedBundleArray release], touchedBundleArray = nil;
if(commandBundleTree) [commandBundleTree release], commandBundleTree = nil;
if(sortDescriptor) [sortDescriptor release], sortDescriptor = nil;
@@ -306,6 +308,48 @@
[commandBundleTreeController setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];
+ shellVariableSuggestions = [[NSArray arrayWithObjects:
+ @"SP_ALL_DATABASES",
+ @"SP_ALL_FUNCTIONS",
+ @"SP_ALL_PROCEDURES",
+ @"SP_ALL_TABLES",
+ @"SP_ALL_VIEWS",
+ @"SP_APP_RESOURCES_DIRECTORY",
+ @"SP_BUNDLE_EXIT_INSERT_AS_SNIPPET",
+ @"SP_BUNDLE_EXIT_INSERT_AS_TEXT",
+ @"SP_BUNDLE_EXIT_NONE",
+ @"SP_BUNDLE_EXIT_REPLACE_CONTENT",
+ @"SP_BUNDLE_EXIT_REPLACE_SELECTION",
+ @"SP_BUNDLE_EXIT_SHOW_AS_HTML",
+ @"SP_BUNDLE_EXIT_SHOW_AS_HTML_TOOLTIP",
+ @"SP_BUNDLE_EXIT_SHOW_AS_TEXT_TOOLTIP",
+ @"SP_BUNDLE_INPUT",
+ @"SP_BUNDLE_INPUT_TABLE_METADATA",
+ @"SP_BUNDLE_PATH",
+ @"SP_BUNDLE_SCOPE",
+ @"SP_CURRENT_HOST",
+ @"SP_CURRENT_LINE",
+ @"SP_CURRENT_PORT",
+ @"SP_CURRENT_QUERY",
+ @"SP_CURRENT_USER",
+ @"SP_CURRENT_WORD",
+ @"SP_DATABASE_ENCODING",
+ @"SP_ICON_FILE",
+ @"SP_PROCESS_ID",
+ @"SP_QUERY_FILE",
+ @"SP_QUERY_RESULT_FILE",
+ @"SP_QUERY_RESULT_META_FILE",
+ @"SP_QUERY_RESULT_STATUS_FILE",
+ @"SP_RDBMS_TYPE",
+ @"SP_RDBMS_VERSION",
+ @"SP_SELECTED_DATABASE",
+ @"SP_SELECTED_ROW_INDICES",
+ @"SP_SELECTED_TABLE",
+ @"SP_SELECTED_TABLES",
+ @"SP_USED_QUERY_FOR_TABLE",
+ nil
+ ] retain];
+
[self _initTree];
}
@@ -662,6 +706,9 @@
*/
- (IBAction)removeCommandBundle:(id)sender
{
+
+ [commandsOutlineView abortEditing];
+
NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Remove selected Bundle?", @"remove selected bundle message")
defaultButton:NSLocalizedString(@"Remove", @"remove button")
alternateButton:NSLocalizedString(@"Cancel", @"cancel button")
@@ -745,6 +792,12 @@
}
+- (IBAction)performClose:(id)sender
+{
+ [self _initTree];
+ [self close];
+}
+
/**
* Save all touched bundles to disk and close the Bundle Editor window
*/
@@ -1451,10 +1504,23 @@
cycleCounter = 0;
}
- [self performSelector:@selector(setAllowedUndo) withObject:nil afterDelay:0.09];
+ [self performSelector:@selector(setAllowedUndo) withObject:nil afterDelay:0.0005];
}
}
+/**
+ * Add shell variable names to the completion list
+ */
+- (NSArray *)textView:(NSTextView *)textView completions:(NSArray *)words forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index
+{
+
+ NSMutableArray *suggestions = [NSMutableArray array];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF BEGINSWITH %@ ", [[textView string] substringWithRange:charRange]];
+ [suggestions addObjectsFromArray:[shellVariableSuggestions filteredArrayUsingPredicate:predicate]];
+ [suggestions addObjectsFromArray:words];
+ return suggestions;
+
+}
#pragma mark -
#pragma mark UndoManager methods
diff --git a/Source/SPConstants.h b/Source/SPConstants.h
index 393c8fba..09763e45 100644
--- a/Source/SPConstants.h
+++ b/Source/SPConstants.h
@@ -469,6 +469,7 @@ extern NSString *SPBundleFileInputSourceFallBackKey;
extern NSString *SPBundleFileOutputActionKey;
extern NSString *SPBundleFileKeyEquivalentKey;
extern NSString *SPBundleFileInternalKeyEquivalentKey;
+extern NSString *SPBundleFileInternalexecutionUUID;
extern NSString *SPBundleFileTooltipKey;
extern NSString *SPBundleFileDisabledKey;
extern NSString *SPBundleFileAuthorKey;
@@ -482,8 +483,31 @@ extern NSString *SPBundleInternPathToFileKey;
extern NSString *SPBundleInternKeyEquivalentKey;
extern NSString *SPBundleFileName;
extern NSString *SPBundleTaskInputFilePath;
+extern NSString *SPBundleTaskOutputFilePath;
extern NSString *SPBundleTaskScriptCommandFilePath;
extern NSString *SPBundleTaskCopyBlobFileDirectory;
+extern NSString *SPBundleTaskTableMetaDataFilePath;
+
+extern NSString *SPBundleShellVariableInputFilePath;
+extern NSString *SPBundleShellVariableOutputFilePath;
+extern NSString *SPBundleShellVariableBundlePath;
+extern NSString *SPBundleShellVariableBlobFileDirectory;
+extern NSString *SPBundleShellVariableQueryFile;
+extern NSString *SPBundleShellVariableQueryResultFile;
+extern NSString *SPBundleShellVariableQueryResultStatusFile;
+extern NSString *SPBundleShellVariableQueryResultMetaFile;
+extern NSString *SPBundleShellVariableInputTableMetaData;
+extern NSString *SPBundleShellVariableScope;
+
+extern const NSInteger SPBundleRedirectActionNone;
+extern const NSInteger SPBundleRedirectActionReplaceSection;
+extern const NSInteger SPBundleRedirectActionReplaceContent;
+extern const NSInteger SPBundleRedirectActionInsertAsText;
+extern const NSInteger SPBundleRedirectActionInsertAsSnippet;
+extern const NSInteger SPBundleRedirectActionShowAsHTML;
+extern const NSInteger SPBundleRedirectActionShowAsTextTooltip;
+extern const NSInteger SPBundleRedirectActionShowAsHTMLTooltip;
+extern const NSInteger SPBundleRedirectActionLastCode;
// sequel URL scheme
extern NSString *SPURLSchemeQueryInputPathHeader;
diff --git a/Source/SPConstants.m b/Source/SPConstants.m
index c7adb047..1ef054bb 100644
--- a/Source/SPConstants.m
+++ b/Source/SPConstants.m
@@ -281,6 +281,7 @@ NSString *SPBundleFileInputSourceFallBackKey = @"input_fallback";
NSString *SPBundleFileOutputActionKey = @"output";
NSString *SPBundleFileKeyEquivalentKey = @"keyEquivalent";
NSString *SPBundleFileInternalKeyEquivalentKey = @"internalKeyEquivalent";
+NSString *SPBundleFileInternalexecutionUUID = @"exeUUID";
NSString *SPBundleFileTooltipKey = @"tooltip";
NSString *SPBundleFileDisabledKey = @"disabled";
NSString *SPBundleFileAuthorKey = @"author";
@@ -294,9 +295,32 @@ NSString *SPBundleInternPathToFileKey = @"path";
NSString *SPBundleInternKeyEquivalentKey = @"keyEquivalent";
NSString *SPBundleFileName = @"command.plist";
-NSString *SPBundleTaskInputFilePath = @"/tmp/SP_BUNDLE_TASK_INPUT";
-NSString *SPBundleTaskScriptCommandFilePath = @"/tmp/SP_SCRIPT_COMMAND";
-NSString *SPBundleTaskCopyBlobFileDirectory = @"/tmp/SP_COPY_BLOB_FILES";
+NSString *SPBundleTaskInputFilePath = @"/tmp/SP_BUNDLE_INPUT";
+NSString *SPBundleTaskOutputFilePath = @"/tmp/SP_BUNDLE_OUTPUT";
+NSString *SPBundleTaskScriptCommandFilePath = @"/tmp/SP_BUNDLE_SCRIPT_COMMAND";
+NSString *SPBundleTaskCopyBlobFileDirectory = @"/tmp/SP_BUNDLE_COPY_BLOB_FILES";
+NSString *SPBundleTaskTableMetaDataFilePath = @"/tmp/SP_BUNDLE_TABLE_META_DATA";
+
+NSString *SPBundleShellVariableInputFilePath = @"SP_BUNDLE_INPUT";
+NSString *SPBundleShellVariableOutputFilePath = @"SP_BUNDLE_OUTPUT";
+NSString *SPBundleShellVariableBundlePath = @"SP_BUNDLE_PATH";
+NSString *SPBundleShellVariableBlobFileDirectory = @"SP_BUNDLE_BLOB_FILES_DIRECTORY";
+NSString *SPBundleShellVariableQueryFile = @"SP_QUERY_FILE";
+NSString *SPBundleShellVariableQueryResultFile = @"SP_QUERY_RESULT_FILE";
+NSString *SPBundleShellVariableQueryResultStatusFile = @"SP_QUERY_RESULT_STATUS_FILE";
+NSString *SPBundleShellVariableQueryResultMetaFile = @"SP_QUERY_RESULT_META_FILE";
+NSString *SPBundleShellVariableInputTableMetaData = @"SP_BUNDLE_INPUT_TABLE_METADATA";
+NSString *SPBundleShellVariableScope = @"SP_BUNDLE_SCOPE";
+
+const NSInteger SPBundleRedirectActionNone = 200;
+const NSInteger SPBundleRedirectActionReplaceSection = 201;
+const NSInteger SPBundleRedirectActionReplaceContent = 202;
+const NSInteger SPBundleRedirectActionInsertAsText = 203;
+const NSInteger SPBundleRedirectActionInsertAsSnippet = 204;
+const NSInteger SPBundleRedirectActionShowAsHTML = 205;
+const NSInteger SPBundleRedirectActionShowAsTextTooltip = 207;
+const NSInteger SPBundleRedirectActionShowAsHTMLTooltip = 208;
+const NSInteger SPBundleRedirectActionLastCode = 208;
// sequel URL scheme
NSString *SPURLSchemeQueryInputPathHeader = @"/tmp/SP_QUERY_";
diff --git a/Source/SPCopyTable.m b/Source/SPCopyTable.m
index 493c3fb4..58339976 100644
--- a/Source/SPCopyTable.m
+++ b/Source/SPCopyTable.m
@@ -922,6 +922,178 @@ NSInteger kBlobAsImageFile = 4;
}
+/**
+ * Only have the copy menu item enabled when row(s) are selected in
+ * supported tables.
+ */
+- (BOOL) validateMenuItem:(NSMenuItem*)anItem
+{
+ NSInteger menuItemTag = [anItem tag];
+
+ // Don't validate anything other than the copy commands
+ if (menuItemTag != MENU_EDIT_COPY && menuItemTag != MENU_EDIT_COPY_WITH_COLUMN && menuItemTag != MENU_EDIT_COPY_AS_SQL) {
+ return YES;
+ }
+
+ // Don't enable menus for relations or triggers - no action to take yet
+ if ([[self delegate] isKindOfClass:[SPTableRelations class]] || [[self delegate] isKindOfClass:[SPTableTriggers class]]) {
+ return NO;
+ }
+
+ // Enable the Copy [with column names] commands if a row is selected
+ if (menuItemTag == MENU_EDIT_COPY || menuItemTag == MENU_EDIT_COPY_WITH_COLUMN) {
+ return ([self numberOfSelectedRows] > 0);
+ }
+
+ // Enable the Copy as SQL commands if rows are selected and column definitions are available
+ if (menuItemTag == MENU_EDIT_COPY_AS_SQL) {
+ return (columnDefinitions != nil && [self numberOfSelectedRows] > 0);
+ }
+
+ return NO;
+}
+
+/**
+ * Trap the enter, escape, tab and arrow keys, overriding default behaviour and continuing/ending editing,
+ * only within the current row.
+ */
+- (BOOL) control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command
+{
+
+ NSUInteger row, column;
+
+ row = [self editedRow];
+ column = [self editedColumn];
+
+ // Trap tab key
+ // -- for handling of blob fields and to check if it's editable look at [[self delegate] control:textShouldBeginEditing:]
+ if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertTab:)] )
+ {
+ [[control window] makeFirstResponder:control];
+
+ // Save the current line if it's the last field in the table
+ if ( [self numberOfColumns] - 1 == column ) {
+ if([[self delegate] respondsToSelector:@selector(addRowToDB)])
+ [[self delegate] addRowToDB];
+ [[self window] makeFirstResponder:self];
+ } else {
+ // Select the next field for editing
+ [self editColumn:column+1 row:row withEvent:nil select:YES];
+ }
+
+ return YES;
+ }
+
+ // Trap shift-tab key
+ else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertBacktab:)] )
+ {
+ [[control window] makeFirstResponder:control];
+
+ // Save the current line if it's the last field in the table
+ if ( column < 1 ) {
+ if([[self delegate] respondsToSelector:@selector(addRowToDB)])
+ [[self delegate] addRowToDB];
+ [[self window] makeFirstResponder:self];
+ } else {
+ // Select the previous field for editing
+ [self editColumn:column-1 row:row withEvent:nil select:YES];
+ }
+
+ return YES;
+ }
+
+ // Trap enter key
+ else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertNewline:)] )
+ {
+ // If enum field is edited RETURN selects the new value instead of saving the entire row
+ if([self isCellComplex])
+ return YES;
+
+ [[control window] makeFirstResponder:control];
+ if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)])
+ [[self delegate] addRowToDB];
+ return YES;
+
+ }
+
+ // Trap down arrow key
+ else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveDown:)] )
+ {
+
+ // If enum field is edited ARROW key navigates through the popup list
+ if([self isCellComplex])
+ return NO;
+
+ NSUInteger newRow = row+1;
+ if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check if we're already at the end of the list
+
+ [[control window] makeFirstResponder:control];
+ if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)])
+ [[self delegate] addRowToDB];
+
+ if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check again. addRowToDB could reload the table and change the number of rows
+ if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too
+
+ [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
+ [self editColumn:column row:newRow withEvent:nil select:YES];
+ return YES;
+ }
+
+ // Trap up arrow key
+ else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveUp:)] )
+ {
+
+ // If enum field is edited ARROW key navigates through the popup list
+ if([self isCellComplex])
+ return NO;
+
+ if (row==0) return YES; //already at the beginning of the list
+ NSUInteger newRow = row-1;
+
+ [[control window] makeFirstResponder:control];
+ if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)])
+ [[self delegate] addRowToDB];
+
+ if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; // addRowToDB could reload the table and change the number of rows
+ if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too
+
+ [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
+ [self editColumn:column row:newRow withEvent:nil select:YES];
+ return YES;
+ }
+
+ return NO;
+}
+
+- (void) keyDown:(NSEvent *)theEvent
+{
+
+ // RETURN or ENTER invoke editing mode for selected row
+ // by calling tableView:shouldEditTableColumn: to validate
+
+ if([self numberOfSelectedRows] == 1 && ([theEvent keyCode] == 36 || [theEvent keyCode] == 76)) {
+ [self editColumn:0 row:[self selectedRow] withEvent:nil select:YES];
+ return;
+ }
+
+ // Check if ESCAPE is hit and use it to cancel row editing if supported
+ if ([theEvent keyCode] == 53 && [[self delegate] respondsToSelector:@selector(cancelRowEditing)])
+ {
+ if ([[self delegate] cancelRowEditing]) return;
+ }
+
+ else if ([theEvent keyCode] == 48 && ([[self delegate] isKindOfClass:[SPCustomQuery class]]
+ || [[self delegate] isKindOfClass:[SPTableContent class]])) {
+ [self editColumn:0 row:[self selectedRow] withEvent:nil select:YES];
+ return;
+ }
+
+ [super keyDown:theEvent];
+}
+
+#pragma mark -
+#pragma mark Bundle Command Support
+
- (IBAction)executeBundleItemForDataTable:(id)sender
{
NSInteger idx = [sender tag] - 1000000;
@@ -964,6 +1136,7 @@ NSInteger kBlobAsImageFile = 4;
NSError *err = nil;
NSString *uuid = [NSString stringWithNewUUID];
NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, uuid];
+ NSString *bundleInputTableMetaDataFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskTableMetaDataFilePath, uuid];
[[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil];
@@ -973,12 +1146,15 @@ NSInteger kBlobAsImageFile = 4;
inputFallBackAction = [[cmdData objectForKey:SPBundleFileInputSourceFallBackKey] lowercaseString];
NSMutableDictionary *env = [NSMutableDictionary dictionary];
- [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:@"SP_BUNDLE_PATH"];
- [env setObject:bundleInputFilePath forKey:@"SP_BUNDLE_INPUT_FILE"];
+ [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:SPBundleShellVariableBundlePath];
+ [env setObject:bundleInputFilePath forKey:SPBundleShellVariableInputFilePath];
if([[self delegate] respondsToSelector:@selector(usedQuery)] && [[self delegate] usedQuery])
[env setObject:[[self delegate] usedQuery] forKey:@"SP_USED_QUERY_FOR_TABLE"];
+ [env setObject:bundleInputTableMetaDataFilePath forKey:SPBundleShellVariableInputTableMetaData];
+ [env setObject:SPBundleScopeDataTable forKey:SPBundleShellVariableScope];
+
if([self numberOfSelectedRows]) {
NSMutableArray *sel = [NSMutableArray array];
NSIndexSet *selectedRows = [self selectedRowIndexes];
@@ -1006,7 +1182,7 @@ NSInteger kBlobAsImageFile = 4;
if(blobHandling != kBlobExclude) {
NSString *bundleBlobFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskCopyBlobFileDirectory, uuid];
- [env setObject:bundleBlobFilePath forKey:@"SP_BUNDLE_BLOB_FILES_DIRECTORY"];
+ [env setObject:bundleBlobFilePath forKey:SPBundleShellVariableBlobFileDirectory];
[self setCopyBlobFileDirectory:bundleBlobFilePath];
} else {
[self setCopyBlobFileDirectory:@""];
@@ -1045,21 +1221,100 @@ NSInteger kBlobAsImageFile = 4;
return;
}
+ NSMutableString *tableMetaData = [NSMutableString string];
+ if([[self delegate] isKindOfClass:[SPCustomQuery class]]) {
+ NSArray *defs = [[self delegate] dataColumnDefinitions];
+ for(NSDictionary* col in defs) {
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"type"]];
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"typegrouping"]];
+ [tableMetaData appendFormat:@"%@\t", ([col objectForKey:@"char_length"]) ? : @""];
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"UNSIGNED_FLAG"]];
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"AUTO_INCREMENT_FLAG"]];
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"PRI_KEY_FLAG"]];
+ [tableMetaData appendString:@"\n"];
+ }
+ }
+ else if([[self delegate] isKindOfClass:[SPTableContent class]]) {
+ NSArray *defs = [[self delegate] dataColumnDefinitions];
+ for(NSDictionary* col in defs) {
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"type"]];
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"typegrouping"]];
+ [tableMetaData appendFormat:@"%@\t", ([col objectForKey:@"length"]) ? : @""];
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"unsigned"]];
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"autoincrement"]];
+ [tableMetaData appendFormat:@"%@\t", ([col objectForKey:@"isprimarykey"]) ? : @"0"];
+ [tableMetaData appendFormat:@"%@\n", [col objectForKey:@"comment"]];
+ }
+ }
+
+ inputFileError = nil;
+ [tableMetaData writeToFile:bundleInputTableMetaDataFilePath
+ atomically:YES
+ encoding:NSUTF8StringEncoding
+ error:&inputFileError];
+
+ if(inputFileError != nil) {
+ NSString *errorMessage = [inputFileError localizedDescription];
+ SPBeginAlertSheet(NSLocalizedString(@"Bundle Error", @"bundle error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [self window], self, nil, nil,
+ [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage]);
+ if (cmdData) [cmdData release];
+ return;
+ }
+
+
NSString *output = [cmd runBashCommandWithEnvironment:env
atCurrentDirectoryPath:nil
callerInstance:[[NSApp delegate] frontDocument]
contextInfo:[NSDictionary dictionaryWithObjectsAndKeys:
([cmdData objectForKey:SPBundleFileNameKey])?:@"-", @"name",
NSLocalizedString(@"Data Table", @"data table menu item label"), @"scope",
+ uuid, SPBundleFileInternalexecutionUUID,
nil]
error:&err];
[[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil];
+ NSString *action = [[cmdData objectForKey:SPBundleFileOutputActionKey] lowercaseString];
+
+ // Redirect due exit code
+ if(err != nil) {
+ if([err code] == SPBundleRedirectActionNone) {
+ action = SPBundleOutputActionNone;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionReplaceSection) {
+ action = SPBundleOutputActionReplaceSelection;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionReplaceContent) {
+ action = SPBundleOutputActionReplaceContent;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionInsertAsText) {
+ action = SPBundleOutputActionInsertAsText;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionInsertAsSnippet) {
+ action = SPBundleOutputActionInsertAsSnippet;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionShowAsHTML) {
+ action = SPBundleOutputActionShowAsHTML;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionShowAsTextTooltip) {
+ action = SPBundleOutputActionShowAsTextTooltip;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionShowAsHTMLTooltip) {
+ action = SPBundleOutputActionShowAsHTMLTooltip;
+ err = nil;
+ }
+ }
+
if(err == nil && output) {
if([cmdData objectForKey:SPBundleFileOutputActionKey] && [[cmdData objectForKey:SPBundleFileOutputActionKey] length]
&& ![[cmdData objectForKey:SPBundleFileOutputActionKey] isEqualToString:SPBundleOutputActionNone]) {
- NSString *action = [[cmdData objectForKey:SPBundleFileOutputActionKey] lowercaseString];
NSPoint pos = [NSEvent mouseLocation];
pos.y -= 16;
@@ -1104,175 +1359,6 @@ NSInteger kBlobAsImageFile = 4;
}
-/**
- * Only have the copy menu item enabled when row(s) are selected in
- * supported tables.
- */
-- (BOOL) validateMenuItem:(NSMenuItem*)anItem
-{
- NSInteger menuItemTag = [anItem tag];
-
- // Don't validate anything other than the copy commands
- if (menuItemTag != MENU_EDIT_COPY && menuItemTag != MENU_EDIT_COPY_WITH_COLUMN && menuItemTag != MENU_EDIT_COPY_AS_SQL) {
- return YES;
- }
-
- // Don't enable menus for relations or triggers - no action to take yet
- if ([[self delegate] isKindOfClass:[SPTableRelations class]] || [[self delegate] isKindOfClass:[SPTableTriggers class]]) {
- return NO;
- }
-
- // Enable the Copy [with column names] commands if a row is selected
- if (menuItemTag == MENU_EDIT_COPY || menuItemTag == MENU_EDIT_COPY_WITH_COLUMN) {
- return ([self numberOfSelectedRows] > 0);
- }
-
- // Enable the Copy as SQL commands if rows are selected and column definitions are available
- if (menuItemTag == MENU_EDIT_COPY_AS_SQL) {
- return (columnDefinitions != nil && [self numberOfSelectedRows] > 0);
- }
-
- return NO;
-}
-
-/**
- * Trap the enter, escape, tab and arrow keys, overriding default behaviour and continuing/ending editing,
- * only within the current row.
- */
-- (BOOL) control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command
-{
-
- NSUInteger row, column;
-
- row = [self editedRow];
- column = [self editedColumn];
-
- // Trap tab key
- // -- for handling of blob fields and to check if it's editable look at [[self delegate] control:textShouldBeginEditing:]
- if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertTab:)] )
- {
- [[control window] makeFirstResponder:control];
-
- // Save the current line if it's the last field in the table
- if ( [self numberOfColumns] - 1 == column ) {
- if([[self delegate] respondsToSelector:@selector(addRowToDB)])
- [[self delegate] addRowToDB];
- [[self window] makeFirstResponder:self];
- } else {
- // Select the next field for editing
- [self editColumn:column+1 row:row withEvent:nil select:YES];
- }
-
- return YES;
- }
-
- // Trap shift-tab key
- else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertBacktab:)] )
- {
- [[control window] makeFirstResponder:control];
-
- // Save the current line if it's the last field in the table
- if ( column < 1 ) {
- if([[self delegate] respondsToSelector:@selector(addRowToDB)])
- [[self delegate] addRowToDB];
- [[self window] makeFirstResponder:self];
- } else {
- // Select the previous field for editing
- [self editColumn:column-1 row:row withEvent:nil select:YES];
- }
-
- return YES;
- }
-
- // Trap enter key
- else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertNewline:)] )
- {
- // If enum field is edited RETURN selects the new value instead of saving the entire row
- if([self isCellComplex])
- return YES;
-
- [[control window] makeFirstResponder:control];
- if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)])
- [[self delegate] addRowToDB];
- return YES;
-
- }
-
- // Trap down arrow key
- else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveDown:)] )
- {
-
- // If enum field is edited ARROW key navigates through the popup list
- if([self isCellComplex])
- return NO;
-
- NSUInteger newRow = row+1;
- if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check if we're already at the end of the list
-
- [[control window] makeFirstResponder:control];
- if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)])
- [[self delegate] addRowToDB];
-
- if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check again. addRowToDB could reload the table and change the number of rows
- if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too
-
- [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
- [self editColumn:column row:newRow withEvent:nil select:YES];
- return YES;
- }
-
- // Trap up arrow key
- else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveUp:)] )
- {
-
- // If enum field is edited ARROW key navigates through the popup list
- if([self isCellComplex])
- return NO;
-
- if (row==0) return YES; //already at the beginning of the list
- NSUInteger newRow = row-1;
-
- [[control window] makeFirstResponder:control];
- if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)])
- [[self delegate] addRowToDB];
-
- if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; // addRowToDB could reload the table and change the number of rows
- if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too
-
- [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO];
- [self editColumn:column row:newRow withEvent:nil select:YES];
- return YES;
- }
-
- return NO;
-}
-
-- (void) keyDown:(NSEvent *)theEvent
-{
-
- // RETURN or ENTER invoke editing mode for selected row
- // by calling tableView:shouldEditTableColumn: to validate
-
- if([self numberOfSelectedRows] == 1 && ([theEvent keyCode] == 36 || [theEvent keyCode] == 76)) {
- [self editColumn:0 row:[self selectedRow] withEvent:nil select:YES];
- return;
- }
-
- // Check if ESCAPE is hit and use it to cancel row editing if supported
- if ([theEvent keyCode] == 53 && [[self delegate] respondsToSelector:@selector(cancelRowEditing)])
- {
- if ([[self delegate] cancelRowEditing]) return;
- }
-
- else if ([theEvent keyCode] == 48 && ([[self delegate] isKindOfClass:[SPCustomQuery class]]
- || [[self delegate] isKindOfClass:[SPTableContent class]])) {
- [self editColumn:0 row:[self selectedRow] withEvent:nil select:YES];
- return;
- }
-
- [super keyDown:theEvent];
-}
-
#pragma mark -
- (void) awakeFromNib
diff --git a/Source/SPCustomQuery.h b/Source/SPCustomQuery.h
index 439ec8e3..f4c2440d 100644
--- a/Source/SPCustomQuery.h
+++ b/Source/SPCustomQuery.h
@@ -216,6 +216,7 @@
- (void) updateTableView;
- (NSIndexSet *) resultSelectedRowIndexes;
- (NSRect) resultViewport;
+- (NSArray *)dataColumnDefinitions;
- (void) setResultSelectedRowIndexesToRestore:(NSIndexSet *)theIndexSet;
- (void) setResultViewportToRestore:(NSRect)theViewport;
- (void) storeCurrentResultViewForRestoration;
diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m
index 5e1a85e4..ef38461c 100644
--- a/Source/SPCustomQuery.m
+++ b/Source/SPCustomQuery.m
@@ -1558,6 +1558,14 @@
}
/**
+ * Provide a getter for the custom query result table's current viewport
+ */
+- (NSArray *)dataColumnDefinitions
+{
+ return cqColumnDefinition;
+}
+
+/**
* Set the selected row indexes to restore on next custom query result table load
*/
- (void) setResultSelectedRowIndexesToRestore:(NSIndexSet *)theIndexSet
diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m
index 4e36c5e1..f1ac803f 100644
--- a/Source/SPDatabaseDocument.m
+++ b/Source/SPDatabaseDocument.m
@@ -4691,6 +4691,28 @@
NSArray *columnDefinition = [theResult fetchResultFieldsStructure];
+ // Write table meta data
+ NSMutableString *tableMetaData = [NSMutableString string];
+ for(NSDictionary* col in columnDefinition) {
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"type"]];
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"typegrouping"]];
+ [tableMetaData appendFormat:@"%@\t", ([col objectForKey:@"char_length"]) ? : @""];
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"UNSIGNED_FLAG"]];
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"AUTO_INCREMENT_FLAG"]];
+ [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"PRI_KEY_FLAG"]];
+ [tableMetaData appendString:@"\n"];
+ }
+ NSError *err = nil;
+ [tableMetaData writeToFile:metaFileName
+ atomically:YES
+ encoding:NSUTF8StringEncoding
+ error:&err];
+ if(err != nil) {
+ NSLog(@"Error while writing “%@”", tableMetaData);
+ NSBeep();
+ return;
+ }
+
// write data
NSInteger i, j;
NSArray *theRow;
diff --git a/Source/SPNarrowDownCompletion.m b/Source/SPNarrowDownCompletion.m
index cdb5c51d..81f4e28b 100644
--- a/Source/SPNarrowDownCompletion.m
+++ b/Source/SPNarrowDownCompletion.m
@@ -115,6 +115,7 @@
if(self = [super initWithContentRect:NSMakeRect(0,0,maxWindowWidth,0) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES])
{
mutablePrefix = [NSMutableString new];
+ originalFilterString = [NSMutableString new];
textualInputCharacters = [[NSMutableCharacterSet alphanumericCharacterSet] retain];
caseSensitive = YES;
filtered = nil;
@@ -124,8 +125,6 @@
suggestions = nil;
autocompletePlaceholderWasInserted = NO;
prefs = [NSUserDefaults standardUserDefaults];
- originalFilterString = [[NSMutableString alloc] init];
- [originalFilterString setString:@""];
tableFont = [NSUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] dataForKey:SPCustomQueryEditorFont]];
[self setupInterface];
@@ -222,13 +221,13 @@
{
// Set filter string
- if(aUserString)
+ if (aUserString) {
[mutablePrefix appendString:aUserString];
+ [originalFilterString appendString:aUserString];
+ }
autoCompletionMode = autoComplete;
- if(autoCompletionMode)
- [originalFilterString appendString:aUserString];
oneColumnMode = oneColumn;
isQueryingDatabaseStructure = isQueryingDBStructure;
@@ -800,13 +799,15 @@
// e.g. for US keyboard "⌥u a" to insert ä
if (([event modifierFlags] & (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask)) == NSAlternateKeyMask || [[event characters] length] == 0)
{
- if(autoCompletionMode) {
- if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:YES];
+ if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:YES];
+
+ if (autoCompletionMode) {
[theView setCompletionIsOpen:NO];
[self close];
[NSApp sendEvent:event];
break;
}
+
[NSApp sendEvent: event];
if(commaInsertionMode)
@@ -845,28 +846,31 @@
}
else if(key == NSBackspaceCharacter || key == NSDeleteCharacter)
{
- if(autoCompletionMode) {
- if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:NO];
+ if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:NO];
+
+ if (autoCompletionMode) {
[NSApp sendEvent:event];
break;
}
+
[NSApp sendEvent:event];
if([mutablePrefix length] == 0 || commaInsertionMode)
break;
spaceCounter = 0;
[mutablePrefix deleteCharactersInRange:NSMakeRange([mutablePrefix length]-1, 1)];
+ [originalFilterString deleteCharactersInRange:NSMakeRange([originalFilterString length]-1, 1)];
theCharRange.length--;
theParseRange.length--;
[self filter];
}
else if([textualInputCharacters characterIsMember:key])
{
+ if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:YES];
- if(autoCompletionMode) {
+ if (autoCompletionMode) {
[theView setCompletionIsOpen:NO];
[self close];
- if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:YES];
[NSApp sendEvent:event];
return;
}
@@ -879,6 +883,7 @@
spaceCounter++;
[mutablePrefix appendString:[event characters]];
+ [originalFilterString appendString:[event characters]];
theCharRange.length++;
theParseRange.length++;
[self filter];
@@ -898,9 +903,7 @@
[self completeAndInsertSnippet];
} else {
if(!NSPointInRect([NSEvent mouseLocation], [self frame])) {
- if(autoCompletionMode) {
- if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:YES];
- }
+ if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:YES];
if(cursorMovedLeft) [theView performSelector:@selector(moveRight:)];
[NSApp sendEvent:event];
break;
@@ -915,7 +918,7 @@
}
// If the autocomplete menu is open, but the placeholder is still present, it needs removing.
- if (autoCompletionMode && autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:NO];
+ if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:NO];
[theView setCompletionIsOpen:NO];
[self close];
@@ -948,7 +951,6 @@
if ([originalFilterString length] < [curMatch length]) {
NSUInteger currentSelectionPosition = [theView selectedRange].location;
NSString* toInsert = [curMatch substringFromIndex:[originalFilterString length]];
- [mutablePrefix appendString:toInsert];
theCharRange.length += [toInsert length] - currentAutocompleteLength;
theParseRange.length += [toInsert length];
[theView insertText:[toInsert lowercaseString]];
diff --git a/Source/SPStringAdditions.m b/Source/SPStringAdditions.m
index a1b0daf8..97339201 100644
--- a/Source/SPStringAdditions.m
+++ b/Source/SPStringAdditions.m
@@ -462,20 +462,21 @@
NSMutableArray *scriptHeaderArguments = [NSMutableArray array];
NSString *scriptPath = @"";
- NSString *stdoutFilePath = [NSString stringWithFormat:@"/tmp/SP_BUNDLE_OUTPUT_FILE_%@", [NSString stringWithNewUUID]];
- NSString *scriptFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskScriptCommandFilePath, [NSString stringWithNewUUID]];
+ NSString *uuid = (contextInfo && [contextInfo objectForKey:SPBundleFileInternalexecutionUUID]) ? [contextInfo objectForKey:@"exeUUID"] : [NSString stringWithNewUUID];
+ NSString *stdoutFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskOutputFilePath, uuid];
+ NSString *scriptFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskScriptCommandFilePath, uuid];
[fm removeItemAtPath:scriptFilePath error:nil];
[fm removeItemAtPath:stdoutFilePath error:nil];
if([[NSApp delegate] lastBundleBlobFilesDirectory] != nil)
[fm removeItemAtPath:[[NSApp delegate] lastBundleBlobFilesDirectory] error:nil];
- if([shellEnvironment objectForKey:@"SP_BUNDLE_BLOB_FILES_DIRECTORY"])
- [[NSApp delegate] setLastBundleBlobFilesDirectory:[shellEnvironment objectForKey:@"SP_BUNDLE_BLOB_FILES_DIRECTORY"]];
+ if([shellEnvironment objectForKey:SPBundleShellVariableBlobFileDirectory])
+ [[NSApp delegate] setLastBundleBlobFilesDirectory:[shellEnvironment objectForKey:SPBundleShellVariableBlobFileDirectory]];
// Parse first line for magic header #! ; if found save the script content and run the command after #! with that file.
// This allows to write perl, ruby, osascript scripts natively.
- if([self length] > 3 && [self hasPrefix:@"#!"] && [shellEnvironment objectForKey:@"SP_BUNDLE_PATH"]) {
+ if([self length] > 3 && [self hasPrefix:@"#!"] && [shellEnvironment objectForKey:SPBundleShellVariableBundlePath]) {
NSRange firstLineRange = NSMakeRange(2, [self rangeOfString:@"\n"].location - 2);
@@ -519,38 +520,66 @@
[theEnv setDictionary:shellEnvironment];
[theEnv setObject:[[NSBundle mainBundle] pathForResource:@"appicon" ofType:@"icns"] forKey:@"SP_ICON_FILE"];
+ [theEnv setObject:[NSString stringWithFormat:@"%@/Contents/Resources", [[NSBundle mainBundle] bundlePath]] forKey:@"SP_APP_RESOURCES_DIRECTORY"];
+ [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionNone] forKey:@"SP_BUNDLE_EXIT_NONE"];
+ [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionReplaceSection] forKey:@"SP_BUNDLE_EXIT_REPLACE_SELECTION"];
+ [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionReplaceContent] forKey:@"SP_BUNDLE_EXIT_REPLACE_CONTENT"];
+ [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionInsertAsText] forKey:@"SP_BUNDLE_EXIT_INSERT_AS_TEXT"];
+ [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionInsertAsSnippet] forKey:@"SP_BUNDLE_EXIT_INSERT_AS_SNIPPET"];
+ [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionShowAsHTML] forKey:@"SP_BUNDLE_EXIT_SHOW_AS_HTML"];
+ [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionShowAsTextTooltip] forKey:@"SP_BUNDLE_EXIT_SHOW_AS_TEXT_TOOLTIP"];
+ [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionShowAsHTMLTooltip] forKey:@"SP_BUNDLE_EXIT_SHOW_AS_HTML_TOOLTIP"];
// Create and set an unique process ID for each SPDatabaseDocument which has to passed
// for each sequelpro:// scheme command as user to be able to identify the url scheme command.
// Furthermore this id is used to communicate with the called command as file name.
- NSString *processID = [NSString stringWithNewUUID];
- [theEnv setObject:processID forKey:@"SP_PROCESS_ID"];
id doc = nil;
if([[[NSApp mainWindow] delegate] respondsToSelector:@selector(selectedTableDocument)])
doc = [[[NSApp mainWindow] delegate] selectedTableDocument];
+ // Check if connected
+ if([[doc connectionID] isEqualToString:@"_"])
+ doc = nil;
+ else {
+ for (NSWindow *aWindow in [NSApp orderedWindows]) {
+ if([[[[aWindow windowController] class] description] isEqualToString:@"SPWindowController"]) {
+ if([[[aWindow windowController] documents] count] && [[[[[[aWindow windowController] documents] objectAtIndex:0] class] description] isEqualToString:@"SPDatabaseDocument"]) {
+ // Check if connected
+ if(![[[[[aWindow windowController] documents] objectAtIndex:0] connectionID] isEqualToString:@"_"])
+ doc = [[[aWindow windowController] documents] objectAtIndex:0];
+ else
+ doc = nil;
+ }
+ }
+ if(doc) break;
+ }
+ }
+
if(doc != nil) {
- [doc setProcessID:processID];
- [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryInputPathHeader, processID] forKey:@"SP_QUERY_FILE"];
- [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultPathHeader, processID] forKey:@"SP_QUERY_RESULT_FILE"];
- [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultStatusPathHeader, processID] forKey:@"SP_QUERY_RESULT_STATUS_FILE"];
- [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultMetaPathHeader, processID] forKey:@"SP_QUERY_RESULT_META_FILE"];
+ [doc setProcessID:uuid];
+
+ [theEnv setObject:uuid forKey:@"SP_PROCESS_ID"];
+ [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryInputPathHeader, uuid] forKey:SPBundleShellVariableQueryFile];
+ [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultPathHeader, uuid] forKey:SPBundleShellVariableQueryResultFile];
+ [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultStatusPathHeader, uuid] forKey:SPBundleShellVariableQueryResultStatusFile];
+ [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultMetaPathHeader, uuid] forKey:SPBundleShellVariableQueryResultMetaFile];
if([doc shellVariables])
[theEnv addEntriesFromDictionary:[doc shellVariables]];
- if(theEnv != nil && [theEnv count])
- [bashTask setEnvironment:theEnv];
}
+ if(theEnv != nil && [theEnv count])
+ [bashTask setEnvironment:theEnv];
+
if(path != nil)
[bashTask setCurrentDirectoryPath:path];
- else if([shellEnvironment objectForKey:@"SP_BUNDLE_PATH"] && [fm fileExistsAtPath:[shellEnvironment objectForKey:@"SP_BUNDLE_PATH"] isDirectory:&isDir] && isDir)
- [bashTask setCurrentDirectoryPath:[shellEnvironment objectForKey:@"SP_BUNDLE_PATH"]];
+ else if([shellEnvironment objectForKey:SPBundleShellVariableBundlePath] && [fm fileExistsAtPath:[shellEnvironment objectForKey:SPBundleShellVariableBundlePath] isDirectory:&isDir] && isDir)
+ [bashTask setCurrentDirectoryPath:[shellEnvironment objectForKey:SPBundleShellVariableBundlePath]];
- // STDOUT will be redirected to /tmp/SP_BUNDLE_OUTPUT_FILE in order to avoid nasty pipe programming due to block size reading
- if([shellEnvironment objectForKey:@"SP_BUNDLE_INPUT_FILE"])
- [bashTask setArguments:[NSArray arrayWithObjects:@"-c", [NSString stringWithFormat:@"%@ > %@ < %@", [scriptHeaderArguments componentsJoinedByString:@" "], stdoutFilePath, [shellEnvironment objectForKey:@"SP_BUNDLE_INPUT_FILE"]], nil]];
+ // STDOUT will be redirected to SPBundleTaskOutputFilePath in order to avoid nasty pipe programming due to block size reading
+ if([shellEnvironment objectForKey:SPBundleShellVariableInputFilePath])
+ [bashTask setArguments:[NSArray arrayWithObjects:@"-c", [NSString stringWithFormat:@"%@ > %@ < %@", [scriptHeaderArguments componentsJoinedByString:@" "], stdoutFilePath, [shellEnvironment objectForKey:SPBundleShellVariableInputFilePath]], nil]];
else
[bashTask setArguments:[NSArray arrayWithObjects:@"-c", [NSString stringWithFormat:@"%@ > %@", [scriptHeaderArguments componentsJoinedByString:@" "], stdoutFilePath], nil]];
@@ -601,14 +630,16 @@
// Remove files
[fm removeItemAtPath:scriptFilePath error:nil];
- if([theEnv objectForKey:@"SP_QUERY_FILE"])
- [fm removeItemAtPath:[theEnv objectForKey:@"SP_QUERY_FILE"] error:nil];
- if([theEnv objectForKey:@"SP_QUERY_RESULT_FILE"])
- [fm removeItemAtPath:[theEnv objectForKey:@"SP_QUERY_RESULT_FILE"] error:nil];
- if([theEnv objectForKey:@"SP_QUERY_RESULT_STATUS_FILE"])
- [fm removeItemAtPath:[theEnv objectForKey:@"SP_QUERY_RESULT_STATUS_FILE"] error:nil];
- if([theEnv objectForKey:@"SP_QUERY_RESULT_META_FILE"])
- [fm removeItemAtPath:[theEnv objectForKey:@"SP_QUERY_RESULT_META_FILE"] error:nil];
+ if([theEnv objectForKey:SPBundleShellVariableQueryFile])
+ [fm removeItemAtPath:[theEnv objectForKey:SPBundleShellVariableQueryFile] error:nil];
+ if([theEnv objectForKey:SPBundleShellVariableQueryResultFile])
+ [fm removeItemAtPath:[theEnv objectForKey:SPBundleShellVariableQueryResultFile] error:nil];
+ if([theEnv objectForKey:SPBundleShellVariableQueryResultStatusFile])
+ [fm removeItemAtPath:[theEnv objectForKey:SPBundleShellVariableQueryResultStatusFile] error:nil];
+ if([theEnv objectForKey:SPBundleShellVariableQueryResultMetaFile])
+ [fm removeItemAtPath:[theEnv objectForKey:SPBundleShellVariableQueryResultMetaFile] error:nil];
+ if([theEnv objectForKey:SPBundleShellVariableInputTableMetaData])
+ [fm removeItemAtPath:[theEnv objectForKey:SPBundleShellVariableInputTableMetaData] error:nil];
// If return from bash re-activate Sequel Pro
[NSApp activateIgnoringOtherApps:YES];
@@ -617,7 +648,7 @@
NSData *errdata = [stderr_file readDataToEndOfFile];
// Check STDERR
- if([errdata length]) {
+ if([errdata length] && (status < SPBundleRedirectActionNone || status > SPBundleRedirectActionLastCode)) {
[fm removeItemAtPath:stdoutFilePath error:nil];
if(status == 9 || userTerminated) return @"";
@@ -658,7 +689,10 @@
} else {
NSBeep();
}
- return @"";
+ if(status > SPBundleRedirectActionNone && status <= SPBundleRedirectActionLastCode)
+ return stdout;
+ else
+ return @"";
}
} else {
NSLog(@"Couldn't read return string from “%@” by using UTF-8 encoding.", self);
diff --git a/Source/SPTableContent.h b/Source/SPTableContent.h
index 96058a0f..1dc4caf9 100644
--- a/Source/SPTableContent.h
+++ b/Source/SPTableContent.h
@@ -218,6 +218,7 @@
- (NSRect) viewport;
- (CGFloat) tablesListWidth;
- (NSDictionary *) filterSettings;
+- (NSArray *)dataColumnDefinitions;
- (void) setSortColumnNameToRestore:(NSString *)theSortColumnName isAscending:(BOOL)isAscending;
- (void) setPageToRestore:(NSUInteger)thePage;
- (void) setSelectedRowIndexesToRestore:(NSIndexSet *)theIndexSet;
diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m
index 483ab35d..4f466470 100644
--- a/Source/SPTableContent.m
+++ b/Source/SPTableContent.m
@@ -3169,6 +3169,14 @@
}
/**
+ * Retrieve the data column definitions
+ */
+- (NSArray *)dataColumnDefinitions
+{
+ return dataColumns;
+}
+
+/**
* Set the sort column and sort order to restore on next table load
*/
- (void) setSortColumnNameToRestore:(NSString *)theSortColumnName isAscending:(BOOL)isAscending
diff --git a/Source/SPTableStructure.m b/Source/SPTableStructure.m
index 79a0a0a2..f57a881f 100644
--- a/Source/SPTableStructure.m
+++ b/Source/SPTableStructure.m
@@ -1015,8 +1015,9 @@
else if ([[theRow objectForKey:@"default"] length] && [theRowType isEqualToString:@"BIT"]) {
[queryString appendFormat:@"\n DEFAULT %@", [theRow objectForKey:@"default"]];
}
- // Suppress appending DEFAULT clause for any numerics, date, time fields if default is empty to avoid error messages
- else if (![[theRow objectForKey:@"default"] length] && ([fieldValidation isFieldTypeNumeric:theRowType] || [fieldValidation isFieldTypeDate:theRowType])) {
+ // Suppress appending DEFAULT clause for any numerics, date, time fields if default is empty to avoid error messages;
+ // also don't specify a default for TEXT/BLOB or geometry fields to avoid strict mode errors
+ else if (![[theRow objectForKey:@"default"] length] && ([fieldValidation isFieldTypeNumeric:theRowType] || [fieldValidation isFieldTypeDate:theRowType] || [theRowType hasSuffix:@"TEXT"] || [theRowType hasSuffix:@"BLOB"] || [fieldValidation isFieldTypeGeometry:theRowType])) {
;
}
// Otherwise, use the provided default
diff --git a/Source/SPTextViewAdditions.m b/Source/SPTextViewAdditions.m
index 10f3f2e5..6ca111b5 100644
--- a/Source/SPTextViewAdditions.m
+++ b/Source/SPTextViewAdditions.m
@@ -527,7 +527,8 @@
NSString *inputAction = @"";
NSString *inputFallBackAction = @"";
NSError *err = nil;
- NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, [NSString stringWithNewUUID]];
+ NSString *uuid = [NSString stringWithNewUUID];
+ NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, uuid];
NSRange currentWordRange, currentSelectionRange, currentLineRange, currentQueryRange;
@@ -573,8 +574,9 @@
}
NSMutableDictionary *env = [NSMutableDictionary dictionary];
- [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:@"SP_BUNDLE_PATH"];
- [env setObject:bundleInputFilePath forKey:@"SP_BUNDLE_INPUT_FILE"];
+ [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:SPBundleShellVariableBundlePath];
+ [env setObject:bundleInputFilePath forKey:SPBundleShellVariableInputFilePath];
+ [env setObject:SPBundleScopeInputField forKey:SPBundleShellVariableScope];
if(selfIsQueryEditor && [[self delegate] currentQueryRange].length)
[env setObject:[[self string] substringWithRange:[[self delegate] currentQueryRange]] forKey:@"SP_CURRENT_QUERY"];
@@ -609,15 +611,53 @@
contextInfo:[NSDictionary dictionaryWithObjectsAndKeys:
([cmdData objectForKey:SPBundleFileNameKey])?:@"-", @"name",
NSLocalizedString(@"Input Field", @"input field menu item label"), @"scope",
+ uuid, SPBundleFileInternalexecutionUUID,
nil]
error:&err];
[[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil];
+ NSString *action = [[cmdData objectForKey:SPBundleFileOutputActionKey] lowercaseString];
+
+ // Redirect due exit code
+ if(err != nil) {
+ if([err code] == SPBundleRedirectActionNone) {
+ action = SPBundleOutputActionNone;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionReplaceSection) {
+ action = SPBundleOutputActionReplaceSelection;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionReplaceContent) {
+ action = SPBundleOutputActionReplaceContent;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionInsertAsText) {
+ action = SPBundleOutputActionInsertAsText;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionInsertAsSnippet) {
+ action = SPBundleOutputActionInsertAsSnippet;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionShowAsHTML) {
+ action = SPBundleOutputActionShowAsHTML;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionShowAsTextTooltip) {
+ action = SPBundleOutputActionShowAsTextTooltip;
+ err = nil;
+ }
+ else if([err code] == SPBundleRedirectActionShowAsHTMLTooltip) {
+ action = SPBundleOutputActionShowAsHTMLTooltip;
+ err = nil;
+ }
+ }
+
if(err == nil && output) {
if([cmdData objectForKey:SPBundleFileOutputActionKey] && [[cmdData objectForKey:SPBundleFileOutputActionKey] length]
&& ![[cmdData objectForKey:SPBundleFileOutputActionKey] isEqualToString:SPBundleOutputActionNone]) {
- NSString *action = [[cmdData objectForKey:SPBundleFileOutputActionKey] lowercaseString];
if([action isEqualToString:SPBundleOutputActionShowAsTextTooltip]) {
[SPTooltip showWithObject:output];