diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/GeneratePreviewForURL.m | 57 | ||||
-rw-r--r-- | Source/SPAppController.m | 609 | ||||
-rw-r--r-- | Source/SPBundleEditorController.m | 65 | ||||
-rw-r--r-- | Source/SPConstants.h | 3 | ||||
-rw-r--r-- | Source/SPConstants.m | 3 | ||||
-rw-r--r-- | Source/SPContentFilterManager.m | 68 | ||||
-rw-r--r-- | Source/SPCopyTable.m | 475 | ||||
-rw-r--r-- | Source/SPCustomQuery.h | 1 | ||||
-rw-r--r-- | Source/SPCustomQuery.m | 75 | ||||
-rw-r--r-- | Source/SPDatabaseDocument.m | 175 | ||||
-rw-r--r-- | Source/SPEditorPreferencePane.m | 321 | ||||
-rw-r--r-- | Source/SPFavoritesController.m | 56 | ||||
-rw-r--r-- | Source/SPFavoritesExporter.m | 23 | ||||
-rw-r--r-- | Source/SPFieldEditorController.m | 30 | ||||
-rw-r--r-- | Source/SPPreferencesUpgrade.m | 23 | ||||
-rw-r--r-- | Source/SPQueryController.m | 47 | ||||
-rw-r--r-- | Source/SPQueryFavoriteManager.h | 6 | ||||
-rw-r--r-- | Source/SPQueryFavoriteManager.m | 60 | ||||
-rw-r--r-- | Source/SPTableContent.m | 37 | ||||
-rw-r--r-- | Source/SPTextView.m | 67 | ||||
-rw-r--r-- | Source/SPTextViewAdditions.m | 433 |
21 files changed, 1406 insertions, 1228 deletions
diff --git a/Source/GeneratePreviewForURL.m b/Source/GeneratePreviewForURL.m index 9dce1011..511a3f2e 100644 --- a/Source/GeneratePreviewForURL.m +++ b/Source/GeneratePreviewForURL.m @@ -145,20 +145,23 @@ void CancelPreviewGeneration(void* thisInterface, QLPreviewRequestRef preview) #pragma mark - NSString *PreviewForSPF(NSURL *myURL, NSInteger *previewHeight) { - + NSDictionary *spf = nil; NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; - NSString *html = nil; - + // Get spf data as dictionary - NSData *pData = [NSData dataWithContentsOfFile:[myURL path] options:NSUncachedRead error:&readError]; - NSDictionary *spf = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable - format:&format - errorDescription:&convError] retain]; + NSData *pData = [NSData dataWithContentsOfFile:[myURL path] + options:NSUncachedRead + error:&readError]; + + if(pData && !readError) { + spf = [[NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&readError] retain]; + } - if(!readError && spf && ![convError length] && (format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { + NSString *html = nil; + if(!readError && spf) { NSString *spfType = [spf objectForKey:SPFFormatKey]; NSString *(*fp)(NSDictionary *spf,NSURL *myURL, NSInteger *previewHeight) = NULL; // Dispatch different spf formats @@ -378,16 +381,21 @@ NSString *PreviewForSPFS(NSURL *myURL,NSInteger *previewHeight) } NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; NSDictionary *spf = nil; // Get info.plist data as dictionary - NSData *pData = [NSData dataWithContentsOfFile:[NSString stringWithFormat:@"%@/info.plist", [myURL path]] options:NSUncachedRead error:&readError]; - spf = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; + NSData *pData = [NSData dataWithContentsOfFile:[[myURL path] stringByAppendingPathComponent:@"info.plist"] + options:NSUncachedRead + error:&readError]; + + if(pData && !readError) { + spf = [[NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&readError] retain]; + } - if(!spf || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { + if(!spf || readError) { [spf release]; return nil; } @@ -434,14 +442,19 @@ NSString *PreviewForSPFS(NSURL *myURL,NSInteger *previewHeight) continue; } // Get info.plist data as dictionary - NSDictionary *sessionSpf; + NSDictionary *sessionSpf = nil; pData = [NSData dataWithContentsOfFile:spfPath options:NSUncachedRead error:&readError]; - sessionSpf = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; + if(pData && !readError) { + sessionSpf = [[NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&readError] retain]; + } - if(!sessionSpf || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { + if(!sessionSpf || readError) { [spfsHTML appendFormat:@" %@ ∅", [tab objectForKey:@"path"]]; - } else { + } + else { NSString *name = @"••••"; NSString *host = @"••••"; diff --git a/Source/SPAppController.m b/Source/SPAppController.m index a0d4c266..2e62725f 100644 --- a/Source/SPAppController.m +++ b/Source/SPAppController.m @@ -453,31 +453,37 @@ - (void)openSessionBundleAtPath:(NSString *)filePath { - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; NSDictionary *spfs = nil; - NSData *pData = [NSData dataWithContentsOfFile:[NSString stringWithFormat:@"%@/info.plist", filePath] options:NSUncachedRead error:&readError]; - - spfs = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; - - if(!spfs || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while reading connection data file", @"error while reading connection data file")] - defaultButton:NSLocalizedString(@"OK", @"OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"Connection data file couldn't be read.", @"error while reading connection data file")]; + { + NSError *error = nil; - [alert setAlertStyle:NSCriticalAlertStyle]; - [alert runModal]; + NSData *pData = [NSData dataWithContentsOfFile:[filePath stringByAppendingPathComponent:@"info.plist"] + options:NSUncachedRead + error:&error]; - if (spfs) [spfs release]; + if(pData && !error) { + spfs = [[NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&error] retain]; + } - return; + if(!spfs || error) { + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while reading connection data file", @"error while reading connection data file") + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"Connection data file couldn't be read. (%@)", @"error while reading connection data file"), [error localizedDescription]]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; + + if (spfs) [spfs release]; + + return; + } } - if([spfs objectForKey:@"windows"] && [[spfs objectForKey:@"windows"] isKindOfClass:[NSArray class]]) { NSFileManager *fileManager = [NSFileManager defaultManager]; @@ -638,79 +644,83 @@ } NSString *newPath = [NSString stringWithFormat:@"%@/%@", bundlePath, [filePath lastPathComponent]]; - - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; + NSDictionary *cmdData = nil; - NSString *infoPath = [NSString stringWithFormat:@"%@/%@", filePath, SPBundleFileName]; - NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&readError]; - - cmdData = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; - - if (!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSLog(@"“%@/%@” file couldn't be read.", filePath, SPBundleFileName); - NSBeep(); - if (cmdData) [cmdData release]; - return; - } - else { - // Check for installed UUIDs - if (![cmdData objectForKey:SPBundleFileUUIDKey]) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while installing Bundle", @"Open Files : Bundle : UUID : Error dialog title")] - defaultButton:NSLocalizedString(@"OK", @"Open Files : Bundle : UUID : OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"The Bundle ‘%@’ has no UUID which is necessary to identify installed Bundles.", @"Open Files : Bundle: UUID : UUID-Attribute is missing in bundle's command.plist file"), [filePath lastPathComponent]]; - - [alert setAlertStyle:NSCriticalAlertStyle]; - [alert runModal]; + { + NSError *error = nil; + + NSString *infoPath = [NSString stringWithFormat:@"%@/%@", filePath, SPBundleFileName]; + NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&error]; + + if(pData && !error) { + cmdData = [[NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&error] retain]; + } + + if (!cmdData || error) { + NSLog(@"“%@/%@” file couldn't be read. (error=%@)", filePath, SPBundleFileName, error); + NSBeep(); if (cmdData) [cmdData release]; return; } + } + + // Check for installed UUIDs + if (![cmdData objectForKey:SPBundleFileUUIDKey]) { + NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while installing Bundle", @"Open Files : Bundle : UUID : Error dialog title")] + defaultButton:NSLocalizedString(@"OK", @"Open Files : Bundle : UUID : OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"The Bundle ‘%@’ has no UUID which is necessary to identify installed Bundles.", @"Open Files : Bundle: UUID : UUID-Attribute is missing in bundle's command.plist file"), [filePath lastPathComponent]]; - // Reload Bundles if Sequel Pro didn't run - if (![installedBundleUUIDs count]) { - [self reloadBundles:self]; - } + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; + if (cmdData) [cmdData release]; + return; + } + + // Reload Bundles if Sequel Pro didn't run + if (![installedBundleUUIDs count]) { + [self reloadBundles:self]; + } + + if ([[installedBundleUUIDs allKeys] containsObject:[cmdData objectForKey:SPBundleFileUUIDKey]]) { + NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Installing Bundle", @"Open Files : Bundle : Already-Installed : 'Update Bundle' question dialog title")] + defaultButton:NSLocalizedString(@"Update", @"Open Files : Bundle : Already-Installed : Update button") + alternateButton:NSLocalizedString(@"Cancel", @"Open Files : Bundle : Already-Installed : Cancel button") + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"A Bundle ‘%@’ is already installed. Do you want to update it?", @"Open Files : Bundle : Already-Installed : 'Update Bundle' question dialog message"), [[installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]] objectForKey:@"name"]]; - if ([[installedBundleUUIDs allKeys] containsObject:[cmdData objectForKey:SPBundleFileUUIDKey]]) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Installing Bundle", @"Open Files : Bundle : Already-Installed : 'Update Bundle' question dialog title")] - defaultButton:NSLocalizedString(@"Update", @"Open Files : Bundle : Already-Installed : Update button") - alternateButton:NSLocalizedString(@"Cancel", @"Open Files : Bundle : Already-Installed : Cancel button") - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"A Bundle ‘%@’ is already installed. Do you want to update it?", @"Open Files : Bundle : Already-Installed : 'Update Bundle' question dialog message"), [[installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]] objectForKey:@"name"]]; + [alert setAlertStyle:NSCriticalAlertStyle]; + NSInteger answer = [alert runModal]; + + if (answer == NSAlertDefaultReturn) { + NSError *error = nil; + NSString *removePath = [[[installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]] objectForKey:@"path"] substringToIndex:([(NSString *)[[installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]] objectForKey:@"path"] length]-[SPBundleFileName length]-1)]; + NSString *moveToTrashCommand = [NSString stringWithFormat:@"osascript -e 'tell application \"Finder\" to move (POSIX file \"%@\") to the trash'", removePath]; - [alert setAlertStyle:NSCriticalAlertStyle]; - NSInteger answer = [alert runModal]; + [SPBundleCommandRunner runBashCommand:moveToTrashCommand withEnvironment:nil atCurrentDirectoryPath:nil error:&error]; - if (answer == NSAlertDefaultReturn) { - NSError *error = nil; - NSString *removePath = [[[installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]] objectForKey:@"path"] substringToIndex:([(NSString *)[[installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]] objectForKey:@"path"] length]-[SPBundleFileName length]-1)]; - NSString *moveToTrashCommand = [NSString stringWithFormat:@"osascript -e 'tell application \"Finder\" to move (POSIX file \"%@\") to the trash'", removePath]; - - [SPBundleCommandRunner runBashCommand:moveToTrashCommand withEnvironment:nil atCurrentDirectoryPath:nil error:&error]; + if (error != nil) { + alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while moving “%@” to Trash.", @"Open Files : Bundle : Already-Installed : Delete-Old-Error : Could not delete old bundle before installing new version."), removePath] + defaultButton:NSLocalizedString(@"OK", @"Open Files : Bundle : Already-Installed : Delete-Old-Error : OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@"%@", [error localizedDescription]]; - if (error != nil) { - alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while moving “%@” to Trash.", @"Open Files : Bundle : Already-Installed : Delete-Old-Error : Could not delete old bundle before installing new version."), removePath] - defaultButton:NSLocalizedString(@"OK", @"Open Files : Bundle : Already-Installed : Delete-Old-Error : OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"%@", [error localizedDescription]]; - - [alert setAlertStyle:NSCriticalAlertStyle]; - [alert runModal]; - if (cmdData) [cmdData release]; - return; - } - } - else { + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; if (cmdData) [cmdData release]; - return; } } + else { + if (cmdData) [cmdData release]; + + return; + } } if (cmdData) [cmdData release]; @@ -1117,157 +1127,160 @@ return; } - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; NSDictionary *cmdData = nil; - NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&readError]; + { + NSError *error = nil; + + NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&error]; + + if(pData && !error) { + cmdData = [[NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&error] retain]; + } + + if(!cmdData || error) { + NSLog(@"“%@” file couldn't be read. (error=%@)", infoPath, error); + NSBeep(); + if (cmdData) [cmdData release]; + return; + } + } - cmdData = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; + if([cmdData objectForKey:SPBundleFileCommandKey] && [(NSString *)[cmdData objectForKey:SPBundleFileCommandKey] length]) { - if(!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSLog(@"“%@” file couldn't be read.", infoPath); - NSBeep(); - if (cmdData) [cmdData release]; - return; - } else { - if([cmdData objectForKey:SPBundleFileCommandKey] && [(NSString *)[cmdData objectForKey:SPBundleFileCommandKey] length]) { - - NSString *cmd = [cmdData objectForKey:SPBundleFileCommandKey]; - NSError *err = nil; - NSString *uuid = [NSString stringWithNewUUID]; - NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, uuid]; - - [[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil]; - - NSMutableDictionary *env = [NSMutableDictionary dictionary]; - [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:SPBundleShellVariableBundlePath]; - [env setObject:bundleInputFilePath forKey:SPBundleShellVariableInputFilePath]; - [env setObject:SPBundleScopeGeneral forKey:SPBundleShellVariableBundleScope]; - [env setObject:SPURLSchemeQueryResultPathHeader forKey:SPBundleShellVariableQueryResultFile]; - [env setObject:SPURLSchemeQueryResultStatusPathHeader forKey:SPBundleShellVariableQueryResultStatusFile]; - - NSString *input = @""; - NSError *inputFileError = nil; - if(input == nil) input = @""; - [input writeToFile:bundleInputFilePath - atomically:YES - encoding:NSUTF8StringEncoding - error:&inputFileError]; - - if(inputFileError != nil) { - NSString *errorMessage = [inputFileError localizedDescription]; - SPOnewayAlertSheet( - NSLocalizedString(@"Bundle Error", @"bundle error"), - [self frontDocumentWindow], - [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] - ); - if (cmdData) [cmdData release]; - return; - } + NSString *cmd = [cmdData objectForKey:SPBundleFileCommandKey]; + NSError *err = nil; + NSString *uuid = [NSString stringWithNewUUID]; + NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, uuid]; - NSString *output = [SPBundleCommandRunner runBashCommand:cmd - withEnvironment:env - atCurrentDirectoryPath:nil - callerInstance:self - 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 = SPBundleOutputActionNone; - if([cmdData objectForKey:SPBundleFileOutputActionKey] && [(NSString *)[cmdData objectForKey:SPBundleFileOutputActionKey] length]) - 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; - } + [[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil]; + + NSMutableDictionary *env = [NSMutableDictionary dictionary]; + [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:SPBundleShellVariableBundlePath]; + [env setObject:bundleInputFilePath forKey:SPBundleShellVariableInputFilePath]; + [env setObject:SPBundleScopeGeneral forKey:SPBundleShellVariableBundleScope]; + [env setObject:SPURLSchemeQueryResultPathHeader forKey:SPBundleShellVariableQueryResultFile]; + [env setObject:SPURLSchemeQueryResultStatusPathHeader forKey:SPBundleShellVariableQueryResultStatusFile]; + + NSString *input = @""; + NSError *inputFileError = nil; + if(input == nil) input = @""; + [input writeToFile:bundleInputFilePath + atomically:YES + encoding:NSUTF8StringEncoding + error:&inputFileError]; + + if(inputFileError != nil) { + NSString *errorMessage = [inputFileError localizedDescription]; + SPOnewayAlertSheet( + NSLocalizedString(@"Bundle Error", @"bundle error"), + [self frontDocumentWindow], + [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] + ); + if (cmdData) [cmdData release]; + return; + } + + NSString *output = [SPBundleCommandRunner runBashCommand:cmd + withEnvironment:env + atCurrentDirectoryPath:nil + callerInstance:self + 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 = SPBundleOutputActionNone; + if([cmdData objectForKey:SPBundleFileOutputActionKey] && [(NSString *)[cmdData objectForKey:SPBundleFileOutputActionKey] length]) + 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(![action isEqualToString:SPBundleOutputActionNone]) { - NSPoint pos = [NSEvent mouseLocation]; - pos.y -= 16; + if(err == nil && output) { + if(![action isEqualToString:SPBundleOutputActionNone]) { + NSPoint pos = [NSEvent mouseLocation]; + pos.y -= 16; - if([action isEqualToString:SPBundleOutputActionShowAsTextTooltip]) { - [SPTooltip showWithObject:output atLocation:pos]; - } + if([action isEqualToString:SPBundleOutputActionShowAsTextTooltip]) { + [SPTooltip showWithObject:output atLocation:pos]; + } - else if([action isEqualToString:SPBundleOutputActionShowAsHTMLTooltip]) { - [SPTooltip showWithObject:output atLocation:pos ofType:@"html"]; - } + else if([action isEqualToString:SPBundleOutputActionShowAsHTMLTooltip]) { + [SPTooltip showWithObject:output atLocation:pos ofType:@"html"]; + } - else if([action isEqualToString:SPBundleOutputActionShowAsHTML]) { - BOOL correspondingWindowFound = NO; - for(id win in [NSApp windows]) { - if([[win delegate] isKindOfClass:[SPBundleHTMLOutputController class]]) { - if([[[win delegate] windowUUID] isEqualToString:[cmdData objectForKey:SPBundleFileUUIDKey]]) { - correspondingWindowFound = YES; - [[win delegate] setDocUUID:uuid]; - [[win delegate] displayHTMLContent:output withOptions:nil]; - break; - } + else if([action isEqualToString:SPBundleOutputActionShowAsHTML]) { + BOOL correspondingWindowFound = NO; + for(id win in [NSApp windows]) { + if([[win delegate] isKindOfClass:[SPBundleHTMLOutputController class]]) { + if([[[win delegate] windowUUID] isEqualToString:[cmdData objectForKey:SPBundleFileUUIDKey]]) { + correspondingWindowFound = YES; + [[win delegate] setDocUUID:uuid]; + [[win delegate] displayHTMLContent:output withOptions:nil]; + break; } } - if(!correspondingWindowFound) { - SPBundleHTMLOutputController *c = [[SPBundleHTMLOutputController alloc] init]; - [c setWindowUUID:[cmdData objectForKey:SPBundleFileUUIDKey]]; - [c setDocUUID:uuid]; - [c displayHTMLContent:output withOptions:nil]; - [SPAppDelegate addHTMLOutputController:c]; - } + } + if(!correspondingWindowFound) { + SPBundleHTMLOutputController *c = [[SPBundleHTMLOutputController alloc] init]; + [c setWindowUUID:[cmdData objectForKey:SPBundleFileUUIDKey]]; + [c setDocUUID:uuid]; + [c displayHTMLContent:output withOptions:nil]; + [SPAppDelegate addHTMLOutputController:c]; } } - } else if([err code] != 9) { // Suppress an error message if command was killed - NSString *errorMessage = [err localizedDescription]; - SPOnewayAlertSheet( - NSLocalizedString(@"BASH Error", @"bash error"), - [NSApp mainWindow], - [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] - ); } - + } else if([err code] != 9) { // Suppress an error message if command was killed + NSString *errorMessage = [err localizedDescription]; + SPOnewayAlertSheet( + NSLocalizedString(@"BASH Error", @"bash error"), + [NSApp mainWindow], + [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] + ); } - if (cmdData) [cmdData release]; - } + if (cmdData) [cmdData release]; } /** @@ -1622,8 +1635,8 @@ NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Bundles Installation Error", @"bundles installation error") defaultButton:NSLocalizedString(@"OK", @"OK button") alternateButton:nil - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"Couldn't create Application Support Bundle folder!\nError: %@", @"Couldn't create Application Support Bundle folder!\nError: %@"), [appPathError localizedDescription]]; + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"Couldn't create Application Support Bundle folder!\nError: %@", @"Couldn't create Application Support Bundle folder!\nError: %@"), [appPathError localizedDescription]]; [alert runModal]; return; @@ -1653,20 +1666,25 @@ foundInstalledBundles = YES; - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; - NSDictionary *cmdData = nil; NSString *infoPath = [NSString stringWithFormat:@"%@/%@/%@", bundlePath, bundle, SPBundleFileName]; - NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&readError]; - - cmdData = [NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError]; - - if(!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSLog(@"“%@” file couldn't be read.", infoPath); - NSBeep(); - continue; + NSDictionary *cmdData = nil; + { + NSError *readError = nil; + + NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&readError]; + + if(pData && !readError) { + cmdData = [NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&readError]; + } + + if(!cmdData || readError) { + NSLog(@"“%@” file couldn't be read. (error=%@)", infoPath, readError); + NSBeep(); + continue; + } } if((![cmdData objectForKey:SPBundleFileDisabledKey] || ![[cmdData objectForKey:SPBundleFileDisabledKey] intValue]) @@ -1698,77 +1716,92 @@ if(doBundleUpdate || [installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]] == nil) { if([installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]]) { - - NSString *oldPath = [NSString stringWithFormat:@"%@/%@/%@", [bundlePaths objectAtIndex:0], bundle, SPBundleFileName]; - readError = nil; - convError = nil; NSDictionary *cmdDataOld = nil; + { + NSError *readError = nil; + + NSString *oldPath = [NSString stringWithFormat:@"%@/%@/%@", [bundlePaths objectAtIndex:0], bundle, SPBundleFileName]; + NSData *pDataOld = [NSData dataWithContentsOfFile:oldPath options:NSUncachedRead error:&readError]; + + if(pDataOld && !readError) { + cmdDataOld = [NSPropertyListSerialization propertyListWithData:pDataOld + options:NSPropertyListImmutable + format:NULL + error:&readError]; + } + + if(!cmdDataOld || readError) { + NSLog(@"“%@” file couldn't be read. (error=%@)", oldPath, readError); + NSBeep(); + continue; + } + } - NSData *pDataOld = [NSData dataWithContentsOfFile:oldPath options:NSUncachedRead error:&readError]; - cmdDataOld = [NSPropertyListSerialization propertyListFromData:pDataOld - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError]; - if(!cmdDataOld || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSLog(@"“%@” file couldn't be read.", oldPath); - NSBeep(); - continue; - } else { - NSString *oldBundle = [NSString stringWithFormat:@"%@/%@", [bundlePaths objectAtIndex:0], bundle]; - // Check for modifications - if([cmdDataOld objectForKey:SPBundleFileDefaultBundleWasModifiedKey]) { - - // Duplicate Bundle, change the UUID and rename the menu label - NSString *duplicatedBundle = [NSString stringWithFormat:@"%@/%@_%ld.%@", [bundlePaths objectAtIndex:0], [bundle substringToIndex:([bundle length] - [SPUserBundleFileExtension length] - 1)], (long)(random() % 35000), SPUserBundleFileExtension]; - if(![[NSFileManager defaultManager] copyItemAtPath:oldBundle toPath:duplicatedBundle error:nil]) { - NSLog(@"Couldn't copy “%@” to update it", bundle); - NSBeep(); - continue; - } - NSError *readError1 = nil; - NSString *convError1 = nil; - NSMutableDictionary *dupData = [NSMutableDictionary dictionary]; - NSString *duplicatedBundleCommand = [NSString stringWithFormat:@"%@/%@", duplicatedBundle, SPBundleFileName]; - NSData *dData = [NSData dataWithContentsOfFile:duplicatedBundleCommand options:NSUncachedRead error:&readError1]; - [dupData setDictionary:[NSPropertyListSerialization propertyListFromData:dData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError1]]; - - if ((!dupData && ![dupData count]) || (readError1 != nil || [convError1 length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0))) { - NSLog(@"“%@” file couldn't be read.", duplicatedBundleCommand); - NSBeep(); - continue; - } + NSString *oldBundle = [NSString stringWithFormat:@"%@/%@", [bundlePaths objectAtIndex:0], bundle]; + // Check for modifications + if([cmdDataOld objectForKey:SPBundleFileDefaultBundleWasModifiedKey]) { + + // Duplicate Bundle, change the UUID and rename the menu label + NSString *duplicatedBundle = [NSString stringWithFormat:@"%@/%@_%ld.%@", [bundlePaths objectAtIndex:0], [bundle substringToIndex:([bundle length] - [SPUserBundleFileExtension length] - 1)], (long)(random() % 35000), SPUserBundleFileExtension]; + if(![[NSFileManager defaultManager] copyItemAtPath:oldBundle toPath:duplicatedBundle error:nil]) { + NSLog(@"Couldn't copy “%@” to update it", bundle); + NSBeep(); + continue; + } + NSString *duplicatedBundleCommand = [NSString stringWithFormat:@"%@/%@", duplicatedBundle, SPBundleFileName]; + NSMutableDictionary *dupData = [NSMutableDictionary dictionary]; + { + NSError *readError = nil; - [dupData setObject:[NSString stringWithNewUUID] forKey:SPBundleFileUUIDKey]; - NSString *orgName = [dupData objectForKey:SPBundleFileNameKey]; - [dupData setObject:[NSString stringWithFormat:@"%@ (user)", orgName] forKey:SPBundleFileNameKey]; - [dupData removeObjectForKey:SPBundleFileIsDefaultBundleKey]; - [dupData writeToFile:duplicatedBundleCommand atomically:YES]; - - error = nil; - NSString *moveToTrashCommand = [NSString stringWithFormat:@"osascript -e 'tell application \"Finder\" to move (POSIX file \"%@\") to the trash'", oldBundle]; + NSData *dData = [NSData dataWithContentsOfFile:duplicatedBundleCommand options:NSUncachedRead error:&readError]; - [SPBundleCommandRunner runBashCommand:moveToTrashCommand withEnvironment:nil atCurrentDirectoryPath:nil error:&error]; - - if(error != nil) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while moving “%@” to Trash.", @"error while moving “%@” to trash"), [[installedBundleUUIDs objectForKey:[cmdDataOld objectForKey:SPBundleFileUUIDKey]] objectForKey:@"path"]] - defaultButton:NSLocalizedString(@"OK", @"OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"%@", [error localizedDescription]]; - - [alert setAlertStyle:NSCriticalAlertStyle]; - [alert runModal]; - continue; + if(dData && !readError) { + NSDictionary *dDict = [NSPropertyListSerialization propertyListWithData:dData + options:NSPropertyListImmutable + format:NULL + error:&readError]; + + if(dDict && !readError) { + [dupData setDictionary:dDict]; + } } - [infoAboutUpdatedDefaultBundles appendFormat:@"• %@\n", orgName]; - } else { - // If no modifications are done simply remove the old one - if(![fm removeItemAtPath:oldBundle error:nil]) { - NSLog(@"Couldn't remove “%@” to update it", bundle); + if (![dupData count] || readError) { + NSLog(@"“%@” file couldn't be read. (error=%@)", duplicatedBundleCommand, readError); NSBeep(); continue; } + } + [dupData setObject:[NSString stringWithNewUUID] forKey:SPBundleFileUUIDKey]; + NSString *orgName = [dupData objectForKey:SPBundleFileNameKey]; + [dupData setObject:[NSString stringWithFormat:@"%@ (user)", orgName] forKey:SPBundleFileNameKey]; + [dupData removeObjectForKey:SPBundleFileIsDefaultBundleKey]; + [dupData writeToFile:duplicatedBundleCommand atomically:YES]; + + error = nil; + NSString *moveToTrashCommand = [NSString stringWithFormat:@"osascript -e 'tell application \"Finder\" to move (POSIX file \"%@\") to the trash'", oldBundle]; + + [SPBundleCommandRunner runBashCommand:moveToTrashCommand withEnvironment:nil atCurrentDirectoryPath:nil error:&error]; + + if(error != nil) { + NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while moving “%@” to Trash.", @"error while moving “%@” to trash"), [[installedBundleUUIDs objectForKey:[cmdDataOld objectForKey:SPBundleFileUUIDKey]] objectForKey:@"path"]] + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@"%@", [error localizedDescription]]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; + continue; + } + [infoAboutUpdatedDefaultBundles appendFormat:@"• %@\n", orgName]; + } else { + // If no modifications are done simply remove the old one + if(![fm removeItemAtPath:oldBundle error:nil]) { + NSLog(@"Couldn't remove “%@” to update it", bundle); + NSBeep(); + continue; } } diff --git a/Source/SPBundleEditorController.m b/Source/SPBundleEditorController.m index ddac2b9e..9d4f43ce 100644 --- a/Source/SPBundleEditorController.m +++ b/Source/SPBundleEditorController.m @@ -939,25 +939,31 @@ if(!isNewBundle) { - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; NSDictionary *cmdData = nil; - NSData *pData = [NSData dataWithContentsOfFile:cmdFilePath options:NSUncachedRead error:&readError]; - cmdData = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; - if(!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSLog(@"“%@” file couldn't be read.", cmdFilePath); - NSBeep(); - if (cmdData) [cmdData release]; - return NO; - } else { - // Check for changes and return if no changes are found - if([[saveDict description] isEqualToString:[cmdData description]]) - return YES; - if([cmdData objectForKey:SPBundleFileIsDefaultBundleKey]) - [saveDict setObject:@YES forKey:SPBundleFileDefaultBundleWasModifiedKey]; + { + NSError *error = nil; + + NSData *pData = [NSData dataWithContentsOfFile:cmdFilePath options:NSUncachedRead error:&error]; + + cmdData = [[NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&error] retain]; + + if(!cmdData || error) { + NSLog(@"“%@” file couldn't be read. (error=%@)", cmdFilePath, error); + NSBeep(); + if (cmdData) [cmdData release]; + return NO; + } } + + // Check for changes and return if no changes are found + if([[saveDict description] isEqualToString:[cmdData description]]) + return YES; + if([cmdData objectForKey:SPBundleFileIsDefaultBundleKey]) + [saveDict setObject:@YES forKey:SPBundleFileDefaultBundleWasModifiedKey]; + if (cmdData) [cmdData release]; } @@ -966,7 +972,6 @@ [saveDict writeToFile:cmdFilePath atomically:YES]; return YES; - } /** @@ -1642,21 +1647,25 @@ for(NSString* bundle in foundBundles) { if(![[[bundle pathExtension] lowercaseString] isEqualToString:[SPUserBundleFileExtension lowercaseString]]) continue; - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; NSDictionary *cmdData = nil; + NSError *readError = nil; + NSString *infoPath = [NSString stringWithFormat:@"%@/%@/%@", bundlePath, bundle, SPBundleFileName]; NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&readError]; - - cmdData = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; - - if(!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSLog(@"“%@/%@” file couldn't be read.", bundle, SPBundleFileName); + + if(pData && !error) { + cmdData = [[NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&readError] retain]; + } + + if(!cmdData || readError) { + NSLog(@"“%@/%@” file couldn't be read. (error=%@)", bundle, SPBundleFileName, readError); NSBeep(); if (cmdData) [cmdData release]; - } else { + } + else { if([cmdData objectForKey:SPBundleFileNameKey] && [[cmdData objectForKey:SPBundleFileNameKey] length] && [cmdData objectForKey:SPBundleFileScopeKey]) { NSMutableDictionary *bundleCommand = [NSMutableDictionary dictionary]; diff --git a/Source/SPConstants.h b/Source/SPConstants.h index 34da4f65..13ec5933 100644 --- a/Source/SPConstants.h +++ b/Source/SPConstants.h @@ -451,6 +451,9 @@ extern NSString *SPSelectionDetailTypePrimaryKeyed; extern NSString *SPSSHEnableMuxingPreference; extern NSString *SPSSHClientPath; extern NSString *SPSSLCipherListKey; +extern NSString *SPQueryFavoritesHaveBeenUpdatedNotification; +extern NSString *SPHistoryItemsHaveBeenUpdatedNotification; +extern NSString *SPContentFiltersHaveBeenUpdatedNotification; // URLs extern NSString *SPDonationsURL; diff --git a/Source/SPConstants.m b/Source/SPConstants.m index 1f27e5f1..60674007 100644 --- a/Source/SPConstants.m +++ b/Source/SPConstants.m @@ -248,6 +248,9 @@ NSString *SPSelectionDetailTypePrimaryKeyed = @"SelectionDetailTypePrimaryK NSString *SPSSHEnableMuxingPreference = @"SSHMultiplexingEnabled"; NSString *SPSSHClientPath = @"SSHClientPath"; NSString *SPSSLCipherListKey = @"SSLCipherList"; +NSString *SPQueryFavoritesHaveBeenUpdatedNotification = @"QueryFavoritesHaveBeenUpdatedNotification"; +NSString *SPHistoryItemsHaveBeenUpdatedNotification = @"HistoryItemsHaveBeenUpdatedNotification"; +NSString *SPContentFiltersHaveBeenUpdatedNotification = @"ContentFiltersHaveBeenUpdatedNotification"; // URLs NSString *SPDonationsURL = @"http://www.sequelpro.com/donate/"; diff --git a/Source/SPContentFilterManager.m b/Source/SPContentFilterManager.m index bf29d15a..d0906c27 100644 --- a/Source/SPContentFilterManager.m +++ b/Source/SPContentFilterManager.m @@ -404,11 +404,8 @@ static NSString *SPExportFilterAction = @"SPExportFilter"; [cf release]; // Inform all opened documents to update the query favorites list - for(id doc in [SPAppDelegate orderedDocuments]) - if([[doc valueForKeyPath:@"tableContentInstance"] respondsToSelector:@selector(setCompareTypes:)]) - [[doc valueForKeyPath:@"tableContentInstance"] setCompareTypes:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:SPContentFiltersHaveBeenUpdatedNotification object:self]; #endif - } } @@ -829,30 +826,36 @@ static NSString *SPExportFilterAction = @"SPExportFilter"; if (returnCode == NSOKButton) { NSString *filename = [[[panel URLs] objectAtIndex:0] path]; - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; + NSInteger insertionIndexStart, insertionIndexEnd; NSDictionary *spf = nil; if([[[filename pathExtension] lowercaseString] isEqualToString:SPFileExtensionDefault]) { - NSData *pData = [NSData dataWithContentsOfFile:filename options:NSUncachedRead error:&readError]; - - spf = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; - - if(!spf || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithString:SP_FILE_PARSER_ERROR_TITLE_STRING] - defaultButton:NSLocalizedString(@"OK", @"OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"File couldn't be read.", @"error while reading data file")]; - - [alert setAlertStyle:NSCriticalAlertStyle]; - [alert runModal]; - if (spf) [spf release]; - return; + { + NSError *error = nil; + + NSData *pData = [NSData dataWithContentsOfFile:filename options:NSUncachedRead error:&error]; + + if(pData && !error) { + spf = [[NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&error] retain]; + } + + if(!spf || error) { + NSAlert *alert = [NSAlert alertWithMessageText:SP_FILE_PARSER_ERROR_TITLE_STRING + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"File couldn't be read. (%@)", @"error while reading data file"), [error localizedDescription]]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; + if (spf) [spf release]; + return; + } } if([[spf objectForKey:SPContentFilters] objectForKey:filterType] && [[[spf objectForKey:SPContentFilters] objectForKey:filterType] count]) { @@ -935,27 +938,26 @@ static NSString *SPExportFilterAction = @"SPExportFilter"; [cfdata setObject:filterData forKey:filterType]; [spfdata setObject:cfdata forKey:SPContentFilters]; - NSString *err = nil; - NSData *plist = [NSPropertyListSerialization dataFromPropertyList:spfdata - format:NSPropertyListXMLFormat_v1_0 - errorDescription:&err]; + NSError *error = nil; + NSData *plist = [NSPropertyListSerialization dataWithPropertyList:spfdata + format:NSPropertyListXMLFormat_v1_0 + options:0 + error:&error]; - if(err != nil) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithString:NSLocalizedString(@"Error while converting content filter data", @"Content filters could not be converted to plist upon export - message title (ContentFilterManager)")] + if(error) { + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while converting content filter data", @"Content filters could not be converted to plist upon export - message title (ContentFilterManager)") defaultButton:NSLocalizedString(@"OK", @"OK button") alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"%@", err]; + otherButton:nil + informativeTextWithFormat:@"%@", [error localizedDescription]]; [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; return; } - NSError *error = nil; [plist writeToURL:[panel URL] options:NSAtomicWrite error:&error]; if (error) [[NSAlert alertWithError:error] runModal]; - } } #endif diff --git a/Source/SPCopyTable.m b/Source/SPCopyTable.m index aa77ffbc..5b5c0ae9 100644 --- a/Source/SPCopyTable.m +++ b/Source/SPCopyTable.m @@ -1257,275 +1257,280 @@ static const NSInteger kBlobAsImageFile = 4; return; } - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; NSDictionary *cmdData = nil; - NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&readError]; + { + NSError *error = nil; + + NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&error]; - cmdData = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; + if(pData && !error) { + cmdData = [[NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&error] retain]; + } + + if(!cmdData || error) { + NSLog(@"“%@” file couldn't be read. (error=%@)", infoPath, error); + NSBeep(); + if (cmdData) [cmdData release]; + return; + } + } - if(!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSLog(@"“%@” file couldn't be read.", infoPath); - NSBeep(); - if (cmdData) [cmdData release]; - return; - } else { - if([cmdData objectForKey:SPBundleFileCommandKey] && [(NSString *)[cmdData objectForKey:SPBundleFileCommandKey] length]) { + if([cmdData objectForKey:SPBundleFileCommandKey] && [(NSString *)[cmdData objectForKey:SPBundleFileCommandKey] length]) { - NSString *cmd = [cmdData objectForKey:SPBundleFileCommandKey]; - NSString *inputAction = @""; - NSString *inputFallBackAction = @""; - NSError *err = nil; - NSString *uuid = [NSString stringWithNewUUID]; - NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, uuid]; - NSString *bundleInputTableMetaDataFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskTableMetaDataFilePath, uuid]; + NSString *cmd = [cmdData objectForKey:SPBundleFileCommandKey]; + NSString *inputAction = @""; + NSString *inputFallBackAction = @""; + 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]; + [[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil]; - if([cmdData objectForKey:SPBundleFileInputSourceKey]) - inputAction = [[cmdData objectForKey:SPBundleFileInputSourceKey] lowercaseString]; - if([cmdData objectForKey:SPBundleFileInputSourceFallBackKey]) - inputFallBackAction = [[cmdData objectForKey:SPBundleFileInputSourceFallBackKey] lowercaseString]; + 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:SPBundleShellVariableBundlePath]; - [env setObject:bundleInputFilePath forKey:SPBundleShellVariableInputFilePath]; + NSMutableDictionary *env = [NSMutableDictionary dictionary]; + [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:SPBundleShellVariableBundlePath]; + [env setObject:bundleInputFilePath forKey:SPBundleShellVariableInputFilePath]; - if ([[self delegate] respondsToSelector:@selector(usedQuery)] && [(id <SPDatabaseContentViewDelegate>)[self delegate] usedQuery]) { - [env setObject:[(id <SPDatabaseContentViewDelegate>)[self delegate] usedQuery] forKey:SPBundleShellVariableUsedQueryForTable]; - } + if ([[self delegate] respondsToSelector:@selector(usedQuery)] && [(id <SPDatabaseContentViewDelegate>)[self delegate] usedQuery]) { + [env setObject:[(id <SPDatabaseContentViewDelegate>)[self delegate] usedQuery] forKey:SPBundleShellVariableUsedQueryForTable]; + } - [env setObject:bundleInputTableMetaDataFilePath forKey:SPBundleShellVariableInputTableMetaData]; - [env setObject:SPBundleScopeDataTable forKey:SPBundleShellVariableBundleScope]; + [env setObject:bundleInputTableMetaDataFilePath forKey:SPBundleShellVariableInputTableMetaData]; + [env setObject:SPBundleScopeDataTable forKey:SPBundleShellVariableBundleScope]; - if([self numberOfSelectedRows]) { - NSMutableArray *sel = [NSMutableArray array]; - NSIndexSet *selectedRows = [self selectedRowIndexes]; - [selectedRows enumerateIndexesUsingBlock:^(NSUInteger rowIndex, BOOL * _Nonnull stop) { - [sel addObject:[NSString stringWithFormat:@"%llu", (unsigned long long)rowIndex]]; - }]; - [env setObject:[sel componentsJoinedByString:@"\t"] forKey:SPBundleShellVariableSelectedRowIndices]; - } + if([self numberOfSelectedRows]) { + NSMutableArray *sel = [NSMutableArray array]; + NSIndexSet *selectedRows = [self selectedRowIndexes]; + [selectedRows enumerateIndexesUsingBlock:^(NSUInteger rowIndex, BOOL * _Nonnull stop) { + [sel addObject:[NSString stringWithFormat:@"%llu", (unsigned long long)rowIndex]]; + }]; + [env setObject:[sel componentsJoinedByString:@"\t"] forKey:SPBundleShellVariableSelectedRowIndices]; + } - NSError *inputFileError = nil; - NSString *input = @""; - NSInteger blobHandling = kBlobExclude; - if([cmdData objectForKey:SPBundleFileWithBlobKey]) { - if([[cmdData objectForKey:SPBundleFileWithBlobKey] isEqualToString:SPBundleInputSourceBlobHandlingExclude]) - blobHandling = kBlobExclude; - else if([[cmdData objectForKey:SPBundleFileWithBlobKey] isEqualToString:SPBundleInputSourceBlobHandlingInclude]) - blobHandling = kBlobInclude; - else if([[cmdData objectForKey:SPBundleFileWithBlobKey] isEqualToString:SPBundleInputSourceBlobHandlingImageFileReference]) - blobHandling = kBlobAsImageFile; - else if([[cmdData objectForKey:SPBundleFileWithBlobKey] isEqualToString:SPBundleInputSourceBlobHandlingFileReference]) - blobHandling = kBlobAsFile; - } + NSError *inputFileError = nil; + NSString *input = @""; + NSInteger blobHandling = kBlobExclude; + if([cmdData objectForKey:SPBundleFileWithBlobKey]) { + if([[cmdData objectForKey:SPBundleFileWithBlobKey] isEqualToString:SPBundleInputSourceBlobHandlingExclude]) + blobHandling = kBlobExclude; + else if([[cmdData objectForKey:SPBundleFileWithBlobKey] isEqualToString:SPBundleInputSourceBlobHandlingInclude]) + blobHandling = kBlobInclude; + else if([[cmdData objectForKey:SPBundleFileWithBlobKey] isEqualToString:SPBundleInputSourceBlobHandlingImageFileReference]) + blobHandling = kBlobAsImageFile; + else if([[cmdData objectForKey:SPBundleFileWithBlobKey] isEqualToString:SPBundleInputSourceBlobHandlingFileReference]) + blobHandling = kBlobAsFile; + } - if(blobHandling != kBlobExclude) { - NSString *bundleBlobFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskCopyBlobFileDirectory, uuid]; - [env setObject:bundleBlobFilePath forKey:SPBundleShellVariableBlobFileDirectory]; - [self setTmpBlobFileDirectory:bundleBlobFilePath]; - } else { - [self setTmpBlobFileDirectory:@""]; - } + if(blobHandling != kBlobExclude) { + NSString *bundleBlobFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskCopyBlobFileDirectory, uuid]; + [env setObject:bundleBlobFilePath forKey:SPBundleShellVariableBlobFileDirectory]; + [self setTmpBlobFileDirectory:bundleBlobFilePath]; + } else { + [self setTmpBlobFileDirectory:@""]; + } - if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsTab]) { - input = [self rowsAsTabStringWithHeaders:YES onlySelectedRows:YES blobHandling:blobHandling]; - } - else if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsCsv]) { - input = [self rowsAsCsvStringWithHeaders:YES onlySelectedRows:YES blobHandling:blobHandling]; - } - else if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsSqlInsert]) { - input = [self rowsAsSqlInsertsOnlySelectedRows:YES]; - } - else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsTab]) { - input = [self rowsAsTabStringWithHeaders:YES onlySelectedRows:NO blobHandling:blobHandling]; - } - else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsCsv]) { - input = [self rowsAsCsvStringWithHeaders:YES onlySelectedRows:NO blobHandling:blobHandling]; - } - else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsSqlInsert]) { - input = [self rowsAsSqlInsertsOnlySelectedRows:NO]; - } - - if(input == nil) input = @""; - [input writeToFile:bundleInputFilePath - atomically:YES - encoding:NSUTF8StringEncoding - error:&inputFileError]; - - if(inputFileError != nil) { - NSString *errorMessage = [inputFileError localizedDescription]; - SPOnewayAlertSheet( - NSLocalizedString(@"Bundle Error", @"bundle error"), - [self window], - [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] - ); - if (cmdData) [cmdData release]; - return; - } + if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsTab]) { + input = [self rowsAsTabStringWithHeaders:YES onlySelectedRows:YES blobHandling:blobHandling]; + } + else if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsCsv]) { + input = [self rowsAsCsvStringWithHeaders:YES onlySelectedRows:YES blobHandling:blobHandling]; + } + else if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsSqlInsert]) { + input = [self rowsAsSqlInsertsOnlySelectedRows:YES]; + } + else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsTab]) { + input = [self rowsAsTabStringWithHeaders:YES onlySelectedRows:NO blobHandling:blobHandling]; + } + else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsCsv]) { + input = [self rowsAsCsvStringWithHeaders:YES onlySelectedRows:NO blobHandling:blobHandling]; + } + else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsSqlInsert]) { + input = [self rowsAsSqlInsertsOnlySelectedRows:NO]; + } + + if(input == nil) input = @""; + [input writeToFile:bundleInputFilePath + atomically:YES + encoding:NSUTF8StringEncoding + error:&inputFileError]; + + if(inputFileError != nil) { + NSString *errorMessage = [inputFileError localizedDescription]; + SPOnewayAlertSheet( + NSLocalizedString(@"Bundle Error", @"bundle error"), + [self window], + [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] + ); + if (cmdData) [cmdData release]; + return; + } - // Create an array of table column mappings for fast iteration - NSArray *columns = [self tableColumns]; - NSUInteger numColumns = [columns count]; - NSUInteger *columnMappings = calloc(numColumns, sizeof(NSUInteger)); - NSUInteger c; - for ( c = 0; c < numColumns; c++ ) - columnMappings[c] = (NSUInteger)[[NSArrayObjectAtIndex(columns, c) identifier] integerValue]; - - NSMutableString *tableMetaData = [NSMutableString string]; - if([[self delegate] isKindOfClass:[SPCustomQuery class]]) { - [env setObject:@"query" forKey:SPBundleShellVariableDataTableSource]; - - NSArray *defs = [(id <SPDatabaseContentViewDelegate>)[self delegate] dataColumnDefinitions]; - - if(defs && [defs count] == numColumns) - for( c = 0; c < numColumns; c++ ) { - NSDictionary *col = NSArrayObjectAtIndex(defs, columnMappings[c]); - [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]]) { - [env setObject:@"content" forKey:SPBundleShellVariableDataTableSource]; - - NSArray *defs = [(id <SPDatabaseContentViewDelegate>)[self delegate] dataColumnDefinitions]; - - if(defs && [defs count] == numColumns) - for( c = 0; c < numColumns; c++ ) { - NSDictionary *col = NSArrayObjectAtIndex(defs, columnMappings[c]); - [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"]]; - } - } - free(columnMappings); + // Create an array of table column mappings for fast iteration + NSArray *columns = [self tableColumns]; + NSUInteger numColumns = [columns count]; + NSUInteger *columnMappings = calloc(numColumns, sizeof(NSUInteger)); + NSUInteger c; + for ( c = 0; c < numColumns; c++ ) + columnMappings[c] = (NSUInteger)[[NSArrayObjectAtIndex(columns, c) identifier] integerValue]; - inputFileError = nil; - [tableMetaData writeToFile:bundleInputTableMetaDataFilePath - atomically:YES - encoding:NSUTF8StringEncoding - error:&inputFileError]; + NSMutableString *tableMetaData = [NSMutableString string]; + if([[self delegate] isKindOfClass:[SPCustomQuery class]]) { + [env setObject:@"query" forKey:SPBundleShellVariableDataTableSource]; - if(inputFileError != nil) { - NSString *errorMessage = [inputFileError localizedDescription]; - SPOnewayAlertSheet( - NSLocalizedString(@"Bundle Error", @"bundle error"), - [self window], - [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] - ); - if (cmdData) [cmdData release]; - return; - } + NSArray *defs = [(id <SPDatabaseContentViewDelegate>)[self delegate] dataColumnDefinitions]; + + if(defs && [defs count] == numColumns) + for( c = 0; c < numColumns; c++ ) { + NSDictionary *col = NSArrayObjectAtIndex(defs, columnMappings[c]); + [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]]) { + [env setObject:@"content" forKey:SPBundleShellVariableDataTableSource]; + + NSArray *defs = [(id <SPDatabaseContentViewDelegate>)[self delegate] dataColumnDefinitions]; + + if(defs && [defs count] == numColumns) + for( c = 0; c < numColumns; c++ ) { + NSDictionary *col = NSArrayObjectAtIndex(defs, columnMappings[c]); + [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"]]; + } + } + free(columnMappings); + inputFileError = nil; + [tableMetaData writeToFile:bundleInputTableMetaDataFilePath + atomically:YES + encoding:NSUTF8StringEncoding + error:&inputFileError]; + + if(inputFileError != nil) { + NSString *errorMessage = [inputFileError localizedDescription]; + SPOnewayAlertSheet( + NSLocalizedString(@"Bundle Error", @"bundle error"), + [self window], + [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] + ); + if (cmdData) [cmdData release]; + return; + } - NSString *output = [SPBundleCommandRunner runBashCommand:cmd withEnvironment:env - atCurrentDirectoryPath:nil - callerInstance:[SPAppDelegate 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 *output = [SPBundleCommandRunner runBashCommand:cmd withEnvironment:env + atCurrentDirectoryPath:nil + callerInstance:[SPAppDelegate frontDocument] + contextInfo:[NSDictionary dictionaryWithObjectsAndKeys: + ([cmdData objectForKey:SPBundleFileNameKey])?:@"-", @"name", + NSLocalizedString(@"Data Table", @"data table menu item label"), @"scope", + uuid, SPBundleFileInternalexecutionUUID, nil] + error:&err]; - NSString *action = SPBundleOutputActionNone; - if([cmdData objectForKey:SPBundleFileOutputActionKey] && [(NSString *)[cmdData objectForKey:SPBundleFileOutputActionKey] length]) - action = [[cmdData objectForKey:SPBundleFileOutputActionKey] lowercaseString]; + [[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil]; - // 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; - } + NSString *action = SPBundleOutputActionNone; + if([cmdData objectForKey:SPBundleFileOutputActionKey] && [(NSString *)[cmdData objectForKey:SPBundleFileOutputActionKey] length]) + 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(![action isEqualToString:SPBundleOutputActionNone]) { - NSPoint pos = [NSEvent mouseLocation]; - pos.y -= 16; + if(err == nil && output) { + if(![action isEqualToString:SPBundleOutputActionNone]) { + NSPoint pos = [NSEvent mouseLocation]; + pos.y -= 16; - if([action isEqualToString:SPBundleOutputActionShowAsTextTooltip]) { - [SPTooltip showWithObject:output atLocation:pos]; - } + if([action isEqualToString:SPBundleOutputActionShowAsTextTooltip]) { + [SPTooltip showWithObject:output atLocation:pos]; + } - else if([action isEqualToString:SPBundleOutputActionShowAsHTMLTooltip]) { - [SPTooltip showWithObject:output atLocation:pos ofType:@"html"]; - } + else if([action isEqualToString:SPBundleOutputActionShowAsHTMLTooltip]) { + [SPTooltip showWithObject:output atLocation:pos ofType:@"html"]; + } - else if([action isEqualToString:SPBundleOutputActionShowAsHTML]) { - BOOL correspondingWindowFound = NO; - for(id win in [NSApp windows]) { - if([[win delegate] isKindOfClass:[SPBundleHTMLOutputController class]]) { - if([[[win delegate] windowUUID] isEqualToString:[cmdData objectForKey:SPBundleFileUUIDKey]]) { - correspondingWindowFound = YES; - [[win delegate] displayHTMLContent:output withOptions:nil]; - break; - } + else if([action isEqualToString:SPBundleOutputActionShowAsHTML]) { + BOOL correspondingWindowFound = NO; + for(id win in [NSApp windows]) { + if([[win delegate] isKindOfClass:[SPBundleHTMLOutputController class]]) { + if([[[win delegate] windowUUID] isEqualToString:[cmdData objectForKey:SPBundleFileUUIDKey]]) { + correspondingWindowFound = YES; + [[win delegate] displayHTMLContent:output withOptions:nil]; + break; } } - if(!correspondingWindowFound) { - SPBundleHTMLOutputController *bundleController = [[SPBundleHTMLOutputController alloc] init]; - [bundleController setWindowUUID:[cmdData objectForKey:SPBundleFileUUIDKey]]; - [bundleController displayHTMLContent:output withOptions:nil]; - [SPAppDelegate addHTMLOutputController:bundleController]; - } + } + if(!correspondingWindowFound) { + SPBundleHTMLOutputController *bundleController = [[SPBundleHTMLOutputController alloc] init]; + [bundleController setWindowUUID:[cmdData objectForKey:SPBundleFileUUIDKey]]; + [bundleController displayHTMLContent:output withOptions:nil]; + [SPAppDelegate addHTMLOutputController:bundleController]; } } - } else if([err code] != 9) { // Suppress an error message if command was killed - NSString *errorMessage = [err localizedDescription]; - SPOnewayAlertSheet( - NSLocalizedString(@"BASH Error", @"bash error"), - [self window], - [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] - ); } + } else if([err code] != 9) { // Suppress an error message if command was killed + NSString *errorMessage = [err localizedDescription]; + SPOnewayAlertSheet( + NSLocalizedString(@"BASH Error", @"bash error"), + [self window], + [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] + ); } - - if (cmdData) [cmdData release]; } + + if (cmdData) [cmdData release]; #endif } diff --git a/Source/SPCustomQuery.h b/Source/SPCustomQuery.h index 7491b304..24695ba2 100644 --- a/Source/SPCustomQuery.h +++ b/Source/SPCustomQuery.h @@ -298,7 +298,6 @@ - (NSRange)currentQueryRange; - (NSString *)buildHistoryString; - (void)addHistoryEntry:(NSString *)entryString; -- (void)historyItemsHaveBeenUpdated:(id)manager; - (void)processFieldEditorResult:(id)data contextInfo:(NSDictionary*)contextInfo; @end diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m index 0f880e8c..bddb0b6c 100644 --- a/Source/SPCustomQuery.m +++ b/Source/SPCustomQuery.m @@ -70,6 +70,8 @@ - (id)_resultDataItemAtRow:(NSInteger)row columnIndex:(NSUInteger)column preserveNULLs:(BOOL)preserveNULLs asPreview:(BOOL)asPreview; + (NSString *)linkToHelpTopic:(NSString *)aTopic; - (void)documentWillClose:(NSNotification *)notification; +- (void)queryFavoritesHaveBeenUpdated:(NSNotification *)notification; +- (void)historyItemsHaveBeenUpdated:(NSNotification *)notification; @end @@ -1619,7 +1621,7 @@ #ifndef SP_CODA if ( [[SPQueryController sharedQueryController] historyForFileURL:[tableDocumentInstance fileURL]] ) - [self performSelectorOnMainThread:@selector(historyItemsHaveBeenUpdated:) withObject:self waitUntilDone:YES]; + [self performSelectorOnMainThread:@selector(historyItemsHaveBeenUpdated:) withObject:nil waitUntilDone:YES]; // Populate query favorites [self queryFavoritesHaveBeenUpdated:nil]; @@ -3367,8 +3369,12 @@ /** * Rebuild history popup menu. + * + * Warning: notification may be nil if invoked directly from within this class. + * + * MUST BE CALLED ON THE UI THREAD! */ -- (void)historyItemsHaveBeenUpdated:(id)manager +- (void)historyItemsHaveBeenUpdated:(NSNotification *)notification { // Abort if the connection has been closed already - sign of a closed window if (![mySQLConnection isConnected]) return; @@ -3390,9 +3396,14 @@ /** * Called by the query favorites manager whenever the query favorites have been updated. */ -- (void)queryFavoritesHaveBeenUpdated:(id)manager +- (void)queryFavoritesHaveBeenUpdated:(NSNotification *)notification { - NSMenuItem *headerMenuItem; + NSURL *fileURL = [tableDocumentInstance fileURL]; + + // Warning: This method may be called before any connection has been made in the current tab (triggered by another tab)! + // There doesn't seem to be a real indicator for this, but fileURL is the closest thing plus we need it below (#2266) + if(!fileURL) return; + NSMenu *menu = [queryFavoritesButton menu]; // Remove all favorites beginning from the end @@ -3400,28 +3411,23 @@ [queryFavoritesButton removeItemAtIndex:[queryFavoritesButton numberOfItems]-1]; // Build document-based list - NSString *tblDocName = [[[[tableDocumentInstance fileURL] absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] lastPathComponent]; - if(!tblDocName) { - //NSMenuItem will not accept nil as title - @throw [NSException exceptionWithName:NSInternalInconsistencyException - reason:[NSString stringWithFormat:@"Document name conversion resulted in nil string!? tableDocumentInstance=%@ fileURL=%@",tableDocumentInstance,[tableDocumentInstance fileURL]] - userInfo:nil]; - } - headerMenuItem = [[NSMenuItem alloc] initWithTitle:tblDocName action:NULL keyEquivalent:@""]; - [headerMenuItem setTag:SP_FAVORITE_HEADER_MENUITEM_TAG]; - [headerMenuItem setToolTip:[NSString stringWithFormat:NSLocalizedString(@"‘%@’ based favorites",@"Query Favorites : List : Section Heading : current connection document : tooltip (arg is the name of the spf file)"), tblDocName]]; - [headerMenuItem setIndentationLevel:0]; - [menu addItem:headerMenuItem]; - [headerMenuItem release]; - for (NSDictionary *favorite in [[SPQueryController sharedQueryController] favoritesForFileURL:[tableDocumentInstance fileURL]]) { + NSString *tblDocName = [[[fileURL absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] lastPathComponent]; + { + NSMenuItem *headerMenuItem = [[NSMenuItem alloc] initWithTitle:tblDocName action:NULL keyEquivalent:@""]; + [headerMenuItem setTag:SP_FAVORITE_HEADER_MENUITEM_TAG]; + [headerMenuItem setToolTip:[NSString stringWithFormat:NSLocalizedString(@"‘%@’ based favorites",@"Query Favorites : List : Section Heading : current connection document : tooltip (arg is the name of the spf file)"), tblDocName]]; + [headerMenuItem setIndentationLevel:0]; + [menu addItem:headerMenuItem]; + [headerMenuItem release]; + } + for (NSDictionary *favorite in [[SPQueryController sharedQueryController] favoritesForFileURL:fileURL]) { if (![favorite isKindOfClass:[NSDictionary class]] || ![favorite objectForKey:@"name"]) continue; NSMutableParagraphStyle *paraStyle = [[[NSMutableParagraphStyle alloc] init] autorelease]; [paraStyle setTabStops:@[]]; [paraStyle addTabStop:[[[NSTextTab alloc] initWithType:NSRightTabStopType location:190.0f] autorelease]]; NSDictionary *attributes = @{NSParagraphStyleAttributeName : paraStyle, NSFontAttributeName : [NSFont systemFontOfSize:11]}; - NSAttributedString *titleString = [[[NSAttributedString alloc] - initWithString:([favorite objectForKey:@"tabtrigger"] && [(NSString*)[favorite objectForKey:@"tabtrigger"] length]) ? [NSString stringWithFormat:@"%@\t%@⇥", [favorite objectForKey:@"name"], [favorite objectForKey:@"tabtrigger"]] : [favorite objectForKey:@"name"] - attributes:attributes] autorelease]; + NSAttributedString *titleString = [[[NSAttributedString alloc] initWithString:([favorite objectForKey:@"tabtrigger"] && [(NSString*)[favorite objectForKey:@"tabtrigger"] length]) ? [NSString stringWithFormat:@"%@\t%@⇥", [favorite objectForKey:@"name"], [favorite objectForKey:@"tabtrigger"]] : [favorite objectForKey:@"name"] + attributes:attributes] autorelease]; NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""]; if ([favorite objectForKey:@"query"]) { [item setToolTip:[NSString stringWithString:[favorite objectForKey:@"query"]]]; @@ -3433,21 +3439,22 @@ } // Build global list - headerMenuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Global",@"Query Favorites : List : Section Heading : global query favorites") action:NULL keyEquivalent:@""]; - [headerMenuItem setTag:SP_FAVORITE_HEADER_MENUITEM_TAG]; - [headerMenuItem setToolTip:NSLocalizedString(@"Globally stored favorites",@"Query Favorites : List : Section Heading : global : tooltip")]; - [headerMenuItem setIndentationLevel:0]; - [menu addItem:headerMenuItem]; - [headerMenuItem release]; + { + NSMenuItem *headerMenuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Global",@"Query Favorites : List : Section Heading : global query favorites") action:NULL keyEquivalent:@""]; + [headerMenuItem setTag:SP_FAVORITE_HEADER_MENUITEM_TAG]; + [headerMenuItem setToolTip:NSLocalizedString(@"Globally stored favorites",@"Query Favorites : List : Section Heading : global : tooltip")]; + [headerMenuItem setIndentationLevel:0]; + [menu addItem:headerMenuItem]; + [headerMenuItem release]; + } for (NSDictionary *favorite in [prefs objectForKey:SPQueryFavorites]) { if (![favorite isKindOfClass:[NSDictionary class]] || ![favorite objectForKey:@"name"]) continue; NSMutableParagraphStyle *paraStyle = [[[NSMutableParagraphStyle alloc] init] autorelease]; [paraStyle setTabStops:@[]]; [paraStyle addTabStop:[[[NSTextTab alloc] initWithType:NSRightTabStopType location:190.0f] autorelease]]; NSDictionary *attributes = @{NSParagraphStyleAttributeName : paraStyle, NSFontAttributeName : [NSFont systemFontOfSize:11]}; - NSAttributedString *titleString = [[[NSAttributedString alloc] - initWithString:([favorite objectForKey:@"tabtrigger"] && [(NSString*)[favorite objectForKey:@"tabtrigger"] length]) ? [NSString stringWithFormat:@"%@\t%@⇥", [favorite objectForKey:@"name"], [favorite objectForKey:@"tabtrigger"]] : [favorite objectForKey:@"name"] - attributes:attributes] autorelease]; + NSAttributedString *titleString = [[[NSAttributedString alloc] initWithString:([favorite objectForKey:@"tabtrigger"] && [(NSString*)[favorite objectForKey:@"tabtrigger"] length]) ? [NSString stringWithFormat:@"%@\t%@⇥", [favorite objectForKey:@"name"], [favorite objectForKey:@"tabtrigger"]] : [favorite objectForKey:@"name"] + attributes:attributes] autorelease]; NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""]; if ([favorite objectForKey:@"query"]) { [item setToolTip:[NSString stringWithString:[favorite objectForKey:@"query"]]]; @@ -3990,6 +3997,14 @@ selector:@selector(documentWillClose:) name:SPDocumentWillCloseNotification object:tableDocumentInstance]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(queryFavoritesHaveBeenUpdated:) + name:SPQueryFavoritesHaveBeenUpdatedNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(historyItemsHaveBeenUpdated:) + name:SPHistoryItemsHaveBeenUpdatedNotification + object:nil]; #ifndef SP_CODA [prefs addObserver:self forKeyPath:SPGlobalResultTableFont options:NSKeyValueObservingOptionNew context:NULL]; diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m index dd781992..2340b97e 100644 --- a/Source/SPDatabaseDocument.m +++ b/Source/SPDatabaseDocument.m @@ -439,8 +439,6 @@ static int64_t SPDatabaseDocumentInstanceCounter = 0; #ifndef SP_CODA // Set the fileURL and init the preferences (query favs, filters, and history) if available for that URL NSURL *newURL = [[SPQueryController sharedQueryController] registerDocumentWithFileURL:[self fileURL] andContextInfo:spfPreferences]; -#warning debug code for #2266 - if(!newURL) NSLog(@"#2266: Trying to set nil fileURL in %s from queryController=%@ oldFileURL=%@ contextInfo=%@", __func__, [SPQueryController sharedQueryController], [self fileURL], spfPreferences); [self setFileURL:newURL]; // ...but hide the icon while the document is temporary @@ -3323,25 +3321,25 @@ static int64_t SPDatabaseDocumentInstanceCounter = 0; } [info setObject:windows forKey:@"windows"]; - NSString *err = nil; - NSData *plist = [NSPropertyListSerialization dataFromPropertyList:info - format:NSPropertyListXMLFormat_v1_0 - errorDescription:&err]; + error = nil; + + NSData *plist = [NSPropertyListSerialization dataWithPropertyList:info + format:NSPropertyListXMLFormat_v1_0 + options:0 + error:&error]; - if(err != nil) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while converting session data", @"error while converting session data")] + if(error) { + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while converting session data", @"error while converting session data") defaultButton:NSLocalizedString(@"OK", @"OK button") alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"%@", err]; + otherButton:nil + informativeTextWithFormat:@"%@", [error localizedDescription]]; [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; return; } - - error = nil; [plist writeToFile:[NSString stringWithFormat:@"%@/info.plist", fileName] options:NSAtomicWrite error:&error]; @@ -3400,36 +3398,42 @@ static int64_t SPDatabaseDocumentInstanceCounter = 0; NSBeep(); return NO; } - - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; + NSMutableDictionary *spf = [[NSMutableDictionary alloc] init]; - - NSData *pData = [NSData dataWithContentsOfFile:fileName options:NSUncachedRead error:&readError]; - - [spf addEntriesFromDictionary:[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError]]; - - if(!spf || ![spf count] || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - - [SPAlertSheets beginWaitingAlertSheetWithTitle:[NSString stringWithFormat:NSLocalizedString(@"Error while reading connection data file", @"error while reading connection data file")] - defaultButton:NSLocalizedString(@"OK", @"OK button") - alternateButton:NSLocalizedString(@"Ignore", @"ignore button") - otherButton:nil - alertStyle:NSCriticalAlertStyle - docWindow:parentWindow - modalDelegate:self - didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) - contextInfo:@"saveDocPrefSheetStatus" - infoText:[NSString stringWithFormat:NSLocalizedString(@"Connection data file “%@” couldn't be read. Please try to save the document under a different name.", @"message error while reading connection data file and suggesting to save it under a differnet name"), [fileName lastPathComponent]] - returnCode:&saveDocPrefSheetStatus]; - - if (spf) [spf release]; - if(saveDocPrefSheetStatus == NSAlertAlternateReturn) - return YES; - - return NO; + { + NSError *error = nil; + + NSData *pData = [NSData dataWithContentsOfFile:fileName options:NSUncachedRead error:&error]; + + if(pData && !error) { + NSDictionary *pDict = [NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&error]; + + if(pDict && !error) { + [spf addEntriesFromDictionary:pDict]; + } + } + + if(![spf count] || error) { + [SPAlertSheets beginWaitingAlertSheetWithTitle:NSLocalizedString(@"Error while reading connection data file", @"error while reading connection data file") + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:NSLocalizedString(@"Ignore", @"ignore button") + otherButton:nil + alertStyle:NSCriticalAlertStyle + docWindow:parentWindow + modalDelegate:self + didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) + contextInfo:@"saveDocPrefSheetStatus" + infoText:[NSString stringWithFormat:NSLocalizedString(@"Connection data file “%@” couldn't be read. Please try to save the document under a different name.\n\nDetails: %@", @"message error while reading connection data file and suggesting to save it under a differnet name"), [fileName lastPathComponent], [error localizedDescription]] + returnCode:&saveDocPrefSheetStatus]; + + if(spf) [spf release]; + if(saveDocPrefSheetStatus == NSAlertAlternateReturn) return YES; + + return NO; + } } // For dispatching later @@ -3445,27 +3449,27 @@ static int64_t SPDatabaseDocumentInstanceCounter = 0; [spf setObject:[[SPQueryController sharedQueryController] contentFilterForFileURL:[self fileURL]] forKey:SPContentFilters]; // Save it again - NSString *err = nil; - NSData *plist = [NSPropertyListSerialization dataFromPropertyList:spf - format:NSPropertyListXMLFormat_v1_0 - errorDescription:&err]; + NSError *error = nil; + NSData *plist = [NSPropertyListSerialization dataWithPropertyList:spf + format:NSPropertyListXMLFormat_v1_0 + options:0 + error:&error]; [spf release]; - if(err != nil) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while converting connection data", @"error while converting connection data")] + if(error) { + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while converting connection data", @"error while converting connection data") defaultButton:NSLocalizedString(@"OK", @"OK button") alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"%@", err]; + otherButton:nil + informativeTextWithFormat:@"%@", [error localizedDescription]]; [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; return NO; } - NSError *error = nil; [plist writeToFile:fileName options:NSAtomicWrite error:&error]; - if(error != nil){ + if(error != nil) { NSAlert *errorAlert = [NSAlert alertWithError:error]; [errorAlert runModal]; return NO; @@ -3474,7 +3478,6 @@ static int64_t SPDatabaseDocumentInstanceCounter = 0; [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:[NSURL fileURLWithPath:fileName]]; return YES; - } // Set up the dictionary to save to file, together with a data store @@ -3544,24 +3547,24 @@ static int64_t SPDatabaseDocumentInstanceCounter = 0; } // Convert to plist - NSString *err = nil; - NSData *plist = [NSPropertyListSerialization dataFromPropertyList:spfStructure + NSError *error = nil; + NSData *plist = [NSPropertyListSerialization dataWithPropertyList:spfStructure format:NSPropertyListXMLFormat_v1_0 - errorDescription:&err]; + options:0 + error:&error]; - if (err != nil) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while converting connection data", @"error while converting connection data")] + if (error) { + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while converting connection data", @"error while converting connection data") defaultButton:NSLocalizedString(@"OK", @"OK button") alternateButton:nil otherButton:nil - informativeTextWithFormat:@"%@", err]; + informativeTextWithFormat:@"%@", [error localizedDescription]]; [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; return NO; } - NSError *error = nil; [plist writeToFile:fileName options:NSAtomicWrite error:&error]; if (error != nil){ NSAlert *errorAlert = [NSAlert alertWithError:error]; @@ -3578,8 +3581,6 @@ static int64_t SPDatabaseDocumentInstanceCounter = 0; [[SPQueryController sharedQueryController] registerDocumentWithFileURL:[NSURL fileURLWithPath:fileName] andContextInfo:preferences]; NSURL *newURL = [NSURL fileURLWithPath:fileName]; -#warning debug code for #2266 - if(!newURL) NSLog(@"#2266: Trying to set nil fileURL in %s from fileName=%@", __func__, fileName); [self setFileURL:newURL]; [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:[NSURL fileURLWithPath:fileName]]; @@ -3593,7 +3594,6 @@ static int64_t SPDatabaseDocumentInstanceCounter = 0; } return YES; - } /** @@ -4954,33 +4954,36 @@ static int64_t SPDatabaseDocumentInstanceCounter = 0; */ - (BOOL)setStateFromConnectionFile:(NSString *)path { - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; - NSString *encryptpw = nil; NSMutableDictionary *data = nil; NSDictionary *spf = nil; - - // Read the property list data, and unserialize it. - NSData *pData = [NSData dataWithContentsOfFile:path options:NSUncachedRead error:&readError]; - - spf = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; - - if (!spf || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while reading connection data file", @"error while reading connection data file")] - defaultButton:NSLocalizedString(@"OK", @"OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"Connection data file couldn't be read.", @"error while reading connection data file")]; - - [alert setAlertStyle:NSCriticalAlertStyle]; - [alert runModal]; - if (spf) [spf release]; - [self closeAndDisconnect]; - return NO; + { + NSError *error = nil; + + // Read the property list data, and unserialize it. + NSData *pData = [NSData dataWithContentsOfFile:path options:NSUncachedRead error:&error]; + + if(pData && !error) { + spf = [[NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&error] retain]; + } + + if (!spf || error) { + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while reading connection data file", @"error while reading connection data file") + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"Connection data file couldn't be read. (%@)", @"error while reading connection data file"), [error localizedDescription]]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; + if (spf) [spf release]; + [self closeAndDisconnect]; + return NO; + } } // If the .spf format is unhandled, error. @@ -5139,8 +5142,6 @@ static int64_t SPDatabaseDocumentInstanceCounter = 0; if (![self isSaveInBundle]) { NSURL *newURL = [NSURL fileURLWithPath:path]; -#warning debug code for #2266 - if(!newURL) NSLog(@"#2266: Trying to set nil fileURL in %s from path=%@", __func__, path); [self setFileURL:newURL]; } diff --git a/Source/SPEditorPreferencePane.m b/Source/SPEditorPreferencePane.m index fba5ff92..54b27ed1 100644 --- a/Source/SPEditorPreferencePane.m +++ b/Source/SPEditorPreferencePane.m @@ -33,6 +33,7 @@ #import "SPColorWellCell.h" #import "SPAlertSheets.h" #import "SPCategoryAdditions.h" +#import "SPFunctions.h" // Constants static NSString *SPSaveColorScheme = @"SaveColorScheme"; @@ -65,34 +66,32 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; editThemeListItems = [[NSArray arrayWithArray:[self _getAvailableThemes]] retain]; - editorColors = - [@[ - SPCustomQueryEditorTextColor, - SPCustomQueryEditorBackgroundColor, - SPCustomQueryEditorCaretColor, - SPCustomQueryEditorCommentColor, - SPCustomQueryEditorSQLKeywordColor, - SPCustomQueryEditorNumericColor, - SPCustomQueryEditorQuoteColor, - SPCustomQueryEditorBacktickColor, - SPCustomQueryEditorVariableColor, - SPCustomQueryEditorHighlightQueryColor, - SPCustomQueryEditorSelectionColor + editorColors = [@[ + SPCustomQueryEditorTextColor, + SPCustomQueryEditorBackgroundColor, + SPCustomQueryEditorCaretColor, + SPCustomQueryEditorCommentColor, + SPCustomQueryEditorSQLKeywordColor, + SPCustomQueryEditorNumericColor, + SPCustomQueryEditorQuoteColor, + SPCustomQueryEditorBacktickColor, + SPCustomQueryEditorVariableColor, + SPCustomQueryEditorHighlightQueryColor, + SPCustomQueryEditorSelectionColor ] retain]; - editorNameForColors = - [@[ - NSLocalizedString(@"Text", @"text label for color table (Prefs > Editor)"), - NSLocalizedString(@"Background", @"background label for color table (Prefs > Editor)"), - NSLocalizedString(@"Caret", @"caret label for color table (Prefs > Editor)"), - NSLocalizedString(@"Comment", @"comment label"), - NSLocalizedString(@"Keyword", @"keyword label for color table (Prefs > Editor)"), - NSLocalizedString(@"Numeric", @"numeric label for color table (Prefs > Editor)"), - NSLocalizedString(@"Quote", @"quote label for color table (Prefs > Editor)"), - NSLocalizedString(@"Backtick Quote", @"backtick quote label for color table (Prefs > Editor)"), - NSLocalizedString(@"Variable", @"variable label for color table (Prefs > Editor)"), - NSLocalizedString(@"Query Background", @"query background label for color table (Prefs > Editor)"), - NSLocalizedString(@"Selection", @"selection label for color table (Prefs > Editor)") + editorNameForColors = [@[ + NSLocalizedString(@"Text", @"text label for color table (Prefs > Editor)"), + NSLocalizedString(@"Background", @"background label for color table (Prefs > Editor)"), + NSLocalizedString(@"Caret", @"caret label for color table (Prefs > Editor)"), + NSLocalizedString(@"Comment", @"comment label"), + NSLocalizedString(@"Keyword", @"keyword label for color table (Prefs > Editor)"), + NSLocalizedString(@"Numeric", @"numeric label for color table (Prefs > Editor)"), + NSLocalizedString(@"Quote", @"quote label for color table (Prefs > Editor)"), + NSLocalizedString(@"Backtick Quote", @"backtick quote label for color table (Prefs > Editor)"), + NSLocalizedString(@"Variable", @"variable label for color table (Prefs > Editor)"), + NSLocalizedString(@"Query Background", @"query background label for color table (Prefs > Editor)"), + NSLocalizedString(@"Selection", @"selection label for color table (Prefs > Editor)") ] retain]; } @@ -192,9 +191,9 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; [NSApp beginSheet:enterNameWindow modalForWindow:[[self view] window] - modalDelegate:self + modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) - contextInfo:SPSaveColorScheme]; + contextInfo:SPSaveColorScheme]; } @@ -222,8 +221,6 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; } } - NSBeep(); - [editThemeListTable reloadData]; } @@ -256,8 +253,6 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; } } - NSBeep(); - [editThemeListTable reloadData]; } @@ -288,17 +283,26 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; [[NSColorPanel sharedColorPanel] close]; [prefs setObject:SPDefaultColorSchemeName forKey:SPCustomQueryEditorThemeName]; - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.000f green:0.455f blue:0.000f alpha:1.000f]] forKey:SPCustomQueryEditorCommentColor]; - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.769f green:0.102f blue:0.086f alpha:1.000f]] forKey:SPCustomQueryEditorQuoteColor]; - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.200f green:0.250f blue:1.000f alpha:1.000f]] forKey:SPCustomQueryEditorSQLKeywordColor]; - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.000f green:0.000f blue:0.658f alpha:1.000f]] forKey:SPCustomQueryEditorBacktickColor]; - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.506f green:0.263f blue:0.000f alpha:1.000f]] forKey:SPCustomQueryEditorNumericColor]; - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.500f green:0.500f blue:0.500f alpha:1.000f]] forKey:SPCustomQueryEditorVariableColor]; - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.950f green:0.950f blue:0.950f alpha:1.000f]] forKey:SPCustomQueryEditorHighlightQueryColor]; - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.7098f green:0.8352f blue:1.000f alpha:1.000f]] forKey:SPCustomQueryEditorSelectionColor]; - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor blackColor]] forKey:SPCustomQueryEditorTextColor]; - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor blackColor]] forKey:SPCustomQueryEditorCaretColor]; - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor whiteColor]] forKey:SPCustomQueryEditorBackgroundColor]; + + NSDictionary *vendorDefaults = [prefs volatileDomainForName:NSRegistrationDomain]; // corresponds to -registerDefaults: in the app controller + + NSArray *copyKeys = @[ + SPCustomQueryEditorCommentColor, + SPCustomQueryEditorQuoteColor, + SPCustomQueryEditorSQLKeywordColor, + SPCustomQueryEditorBacktickColor, + SPCustomQueryEditorNumericColor, + SPCustomQueryEditorVariableColor, + SPCustomQueryEditorHighlightQueryColor, + SPCustomQueryEditorSelectionColor, + SPCustomQueryEditorTextColor, + SPCustomQueryEditorCaretColor, + SPCustomQueryEditorBackgroundColor, + ]; + + for(NSString *key in copyKeys) { + [prefs setObject:[vendorDefaults objectForKey:key] forKey:key]; + } [colorSettingTableView setBackgroundColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorBackgroundColor]]]; [colorSettingTableView reloadData]; @@ -321,9 +325,9 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; [NSApp beginSheet:editThemeListWindow modalForWindow:[[self view] window] - modalDelegate:self + modalDelegate:self didEndSelector:nil - contextInfo:nil]; + contextInfo:nil]; } #pragma mark - @@ -346,7 +350,9 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; */ - (void)updateColorSchemeSelectionMenu { - NSMenuItem *defaultItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Default", @"default label") action:@selector(setDefaultColors:) keyEquivalent:@""]; + NSMenuItem *defaultItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Default", @"default label") + action:@selector(setDefaultColors:) + keyEquivalent:@""]; [defaultItem setTarget:self]; @@ -374,7 +380,9 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; [themeSelectionMenu addItem:[NSMenuItem separatorItem]]; } - NSMenuItem *editItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Edit Theme List…", @"edit theme list label") action:@selector(editThemeList:) keyEquivalent:@""]; + NSMenuItem *editItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Edit Theme List…", @"edit theme list label") + action:@selector(editThemeList:) + keyEquivalent:@""]; [editItem setTarget:self]; @@ -513,7 +521,9 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; NSFileManager *fm = [NSFileManager defaultManager]; if (![fm fileExistsAtPath:themePath isDirectory:nil]) { - if (![fm createDirectoryAtPath:themePath withIntermediateDirectories:YES attributes:nil error:nil]) { + NSError *error = nil; + if (![fm createDirectoryAtPath:themePath withIntermediateDirectories:YES attributes:nil error:&error]) { + SPLog(@"Failed to create directory '%@'. error=%@", themePath, error); NSBeep(); return; } @@ -775,9 +785,13 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; NSFileManager *fm = [NSFileManager defaultManager]; if ([fm fileExistsAtPath:themePath isDirectory:nil]) { - NSArray *allItemsRaw = [fm contentsOfDirectoryAtPath:themePath error:NULL]; + NSError *error = nil; + NSArray *allItemsRaw = [fm contentsOfDirectoryAtPath:themePath error:&error]; - if(!allItemsRaw) return @[]; + if(!allItemsRaw || error) { + SPLog(@"Failed to list contents of path '%@'. error=%@", themePath, error); + return @[]; + } // Filter out all themes NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF ENDSWITH %@", [NSString stringWithFormat:@".%@", SPColorThemeFileExtension]]; @@ -889,17 +903,18 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; [scheme setObject:settings forKey:@"settings"]; - NSString *err = nil; - NSData *plist = [NSPropertyListSerialization dataFromPropertyList:scheme - format:NSPropertyListXMLFormat_v1_0 - errorDescription:&err]; - - if(err != nil) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while converting color scheme data", @"error while converting color scheme data")] - defaultButton:NSLocalizedString(@"OK", @"OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"%@", err]; + NSError *error = nil; + NSData *plist = [NSPropertyListSerialization dataWithPropertyList:scheme + format:NSPropertyListXMLFormat_v1_0 + options:0 + error:&error]; + + if(error) { + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while converting color scheme data", @"error while converting color scheme data") + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@"%@", [error localizedDescription]]; [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; @@ -907,7 +922,6 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; return; } - NSError *error = nil; [plist writeToFile:path options:NSAtomicWrite error:&error]; if (error) [[NSAlert alertWithError:error] runModal]; @@ -915,105 +929,136 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; - (BOOL)_loadColorSchemeFromFile:(NSString *)filename { - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; - NSDictionary *theme = nil; - - NSData *pData = [NSData dataWithContentsOfFile:filename options:NSUncachedRead error:&readError]; - - theme = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; - - if (!theme || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while reading data file", @"error while reading data file")] - defaultButton:NSLocalizedString(@"OK", @"OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"File couldn't be read.", @"error while reading data file")]; + + { + NSError *error = nil; + NSData *pData = [NSData dataWithContentsOfFile:filename options:NSUncachedRead error:&error]; - [alert setAlertStyle:NSCriticalAlertStyle]; - [alert runModal]; - if (theme) [theme release]; - [self updateDisplayColorThemeName]; - return NO; + if(pData && !error) { + theme = [NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&error]; + } + + if (!theme || error) { + NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while reading data file", @"error while reading data file")] + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"File couldn't be read. (%@)", @"error while reading data file"), [error localizedDescription]]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; + + [self updateDisplayColorThemeName]; + return NO; + } } - if ([theme objectForKey:@"settings"] - && [[theme objectForKey:@"settings"] isKindOfClass:[NSArray class]] - && [[theme objectForKey:@"settings"] count] - && [[[theme objectForKey:@"settings"] objectAtIndex:0] isKindOfClass:[NSDictionary class]] - && [[[theme objectForKey:@"settings"] objectAtIndex:0] objectForKey:@"settings"]) { + Class NSDictionaryClass = [NSDictionary class]; + Class NSStringClass = [NSString class]; + + NSUInteger actuallyLoaded = 0; + NSArray *themeElements; + if ([theme isKindOfClass:NSDictionaryClass] + && (themeElements = [theme objectForKey:@"settings"]) + && [themeElements isKindOfClass:[NSArray class]] + && [themeElements count]) { + + NSInteger counter = -1; - NSInteger counter = 0; + NSDictionary *mainPairs = @{ + @"background": SPCustomQueryEditorBackgroundColor, + @"caret": SPCustomQueryEditorCaretColor, + @"foreground": SPCustomQueryEditorTextColor, + @"lineHighlight": SPCustomQueryEditorHighlightQueryColor, + @"selection": SPCustomQueryEditorSelectionColor, + }; - for (NSDictionary *dict in [theme objectForKey:@"settings"]) + NSDictionary *optPairs = @{ + @"Comment": SPCustomQueryEditorCommentColor, + @"String": SPCustomQueryEditorQuoteColor, + @"Keyword": SPCustomQueryEditorSQLKeywordColor, + @"User-defined constant": SPCustomQueryEditorBacktickColor, + @"Number": SPCustomQueryEditorNumericColor, + @"Variable": SPCustomQueryEditorVariableColor, + }; + + for (NSDictionary *dict in themeElements) { + counter++; + + if(![dict isKindOfClass:NSDictionaryClass]) { + SPLog(@"skipping unexpected object at settings[%ld]!",(long)counter); + continue; + } + + //the first item is special and contains all the main theme colors if (counter == 0) { - if ([dict objectForKey:@"settings"]) { - NSDictionary *dic = [dict objectForKey:@"settings"]; - if([dic objectForKey:@"background"]) - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithRGBHexString:[dic objectForKey:@"background"]]] forKey:SPCustomQueryEditorBackgroundColor]; - if([dic objectForKey:@"caret"]) - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithRGBHexString:[dic objectForKey:@"caret"]]] forKey:SPCustomQueryEditorCaretColor]; - if([dic objectForKey:@"foreground"]) - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithRGBHexString:[dic objectForKey:@"foreground"]]] forKey:SPCustomQueryEditorTextColor]; - if([dic objectForKey:@"lineHighlight"]) - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithRGBHexString:[dic objectForKey:@"lineHighlight"]]] forKey:SPCustomQueryEditorHighlightQueryColor]; - if([dic objectForKey:@"selection"]) - [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithRGBHexString:[dic objectForKey:@"selection"]]] forKey:SPCustomQueryEditorSelectionColor]; - } + NSDictionary *dic = [dict objectForKey:@"settings"]; + if ([dic isKindOfClass:NSDictionaryClass]) { + for(NSString *key in mainPairs) { + NSString *rgbHex = [dic objectForKey:key]; + NSColor *color; + if([rgbHex isKindOfClass:NSStringClass] && (color = [NSColor colorWithRGBHexString:rgbHex])) { + [prefs setObject:[NSArchiver archivedDataWithRootObject:color] forKey:[mainPairs objectForKey:key]]; + actuallyLoaded++; + } + else { + SPLog(@"Main color key '%@' is either missing in theme or failed parsing as hex color (at settings[0].settings)!", key); + } + } + } else { - continue; + SPLog(@"Unexpected type for object main settings (at settings[0].settings)"); } } else { - if ([dict objectForKey:@"name"] && [dict objectForKey:@"settings"] && [[dict objectForKey:@"settings"] isKindOfClass:[NSDictionary class]] && [[dict objectForKey:@"settings"] objectForKey:@"foreground"]) { - if ([[dict objectForKey:@"name"] isEqualToString:@"Comment"]) - [prefs setObject:[NSArchiver archivedDataWithRootObject: - [NSColor colorWithRGBHexString:[[dict objectForKey:@"settings"] objectForKey:@"foreground"]]] - forKey:SPCustomQueryEditorCommentColor]; - else if ([[dict objectForKey:@"name"] isEqualToString:@"String"]) - [prefs setObject:[NSArchiver archivedDataWithRootObject: - [NSColor colorWithRGBHexString:[[dict objectForKey:@"settings"] objectForKey:@"foreground"]]] - forKey:SPCustomQueryEditorQuoteColor]; - else if ([[dict objectForKey:@"name"] isEqualToString:@"Keyword"]) - [prefs setObject:[NSArchiver archivedDataWithRootObject: - [NSColor colorWithRGBHexString:[[dict objectForKey:@"settings"] objectForKey:@"foreground"]]] - forKey:SPCustomQueryEditorSQLKeywordColor]; - else if ([[dict objectForKey:@"name"] isEqualToString:@"User-defined constant"]) - [prefs setObject:[NSArchiver archivedDataWithRootObject: - [NSColor colorWithRGBHexString:[[dict objectForKey:@"settings"] objectForKey:@"foreground"]]] - forKey:SPCustomQueryEditorBacktickColor]; - else if ([[dict objectForKey:@"name"] isEqualToString:@"Number"]) - [prefs setObject:[NSArchiver archivedDataWithRootObject: - [NSColor colorWithRGBHexString:[[dict objectForKey:@"settings"] objectForKey:@"foreground"]]] - forKey:SPCustomQueryEditorNumericColor]; - else if ([[dict objectForKey:@"name"] isEqualToString:@"Variable"]) - [prefs setObject:[NSArchiver archivedDataWithRootObject: - [NSColor colorWithRGBHexString:[[dict objectForKey:@"settings"] objectForKey:@"foreground"]]] - forKey:SPCustomQueryEditorVariableColor]; + NSString *optName = [dict objectForKey:@"name"]; + NSDictionary *optSettings = [dict objectForKey:@"settings"]; + + if ([optName isKindOfClass:NSStringClass] && [optSettings isKindOfClass:NSDictionaryClass]) { + NSString *prefName = [optPairs objectForKey:optName]; + if(prefName) { + NSString *rgbHex = [optSettings objectForKey:@"foreground"]; + NSColor *color; + if([rgbHex isKindOfClass:NSStringClass] && (color = [NSColor colorWithRGBHexString:rgbHex])) { + [prefs setObject:[NSArchiver archivedDataWithRootObject:color] forKey:prefName]; + actuallyLoaded++; + } + else { + SPLog(@"Color for entry '%@' is either missing in theme or failed parsing as hex color (at settings[%ld].settings.foreground)!", optName, counter); + } + } + else { + SPLog(@"Skipping unknown color entry '%@' (at settings[%ld].name)", optName, counter); + } + } + else { + SPLog(@"Skipping invalid color entry: Either missing keys and/or unexpected objects (at settings[%ld])!", counter); } } - - counter++; } - - [theme release]; + } + else { + SPLog(@"root key 'settings' is missing, has an unexpected type or is empty in theme file!"); + } + + if(actuallyLoaded > 0) { [colorSettingTableView setBackgroundColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorBackgroundColor]]]; [colorSettingTableView reloadData]; } else { NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while reading data file", @"error while reading data file")] - defaultButton:NSLocalizedString(@"OK", @"OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"No color theme data found.", @"error that no color theme found")]; + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"No color theme data found.", @"error that no color theme found")]; [alert setAlertStyle:NSInformationalAlertStyle]; [alert runModal]; - [theme release]; return NO; } diff --git a/Source/SPFavoritesController.m b/Source/SPFavoritesController.m index 625b46cc..e152a27f 100644 --- a/Source/SPFavoritesController.m +++ b/Source/SPFavoritesController.m @@ -254,10 +254,7 @@ static SPFavoritesController *sharedFavoritesController = nil; if (error) { NSLog(@"Error retrieving data directory path: %@", [error localizedDescription]); - - pthread_mutex_unlock(&favoritesLock); - - return; + goto end_cleanup; } NSString *favoritesFile = [dataPath stringByAppendingPathComponent:SPFavoritesDataFile]; @@ -270,31 +267,27 @@ static SPFavoritesController *sharedFavoritesController = nil; NSMutableDictionary *newFavorites = [NSMutableDictionary dictionaryWithObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"Favorites", @"favorites label"), SPFavoritesGroupNameKey, @[], SPFavoriteChildrenKey, nil] forKey:SPFavoritesRootKey]; error = nil; - NSString *errorString = nil; - NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:newFavorites + NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:newFavorites format:NSPropertyListXMLFormat_v1_0 - errorDescription:&errorString]; - if (plistData) { + options:0 + error:&error]; + if (error) { + NSLog(@"Error converting default favorites data to plist format: %@", error); + goto end_cleanup; + } + else if (plistData) { [plistData writeToFile:favoritesFile options:NSAtomicWrite error:&error]; if (error) { - NSLog(@"Error writing default favorites data: %@", [error localizedDescription]); + NSLog(@"Error writing default favorites data: %@", error); } } - else if (errorString) { - NSLog(@"Error converting default favorites data to plist format: %@", errorString); - - [errorString release]; - - pthread_mutex_unlock(&favoritesLock); - - return; - } favoritesData = newFavorites; } - + +end_cleanup: pthread_mutex_unlock(&favoritesLock); } @@ -396,12 +389,10 @@ static SPFavoritesController *sharedFavoritesController = nil; pthread_mutex_lock(&writeLock); if (!favoritesTree) { - pthread_mutex_unlock(&writeLock); - return; + goto end_cleanup; } NSError *error = nil; - NSString *errorString = nil; // Before starting the file actions, attempt to create a dictionary // from the current favourites tree and convert it to a dictionary representation @@ -409,13 +400,13 @@ static SPFavoritesController *sharedFavoritesController = nil; // be terminated during shutdown. NSDictionary *dictionary = @{SPFavoritesRootKey : data}; - NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:dictionary + NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:dictionary format:NSPropertyListXMLFormat_v1_0 - errorDescription:&errorString]; - if (errorString) { - NSLog(@"Error converting favorites data to plist format: %@", errorString); - - [errorString release]; + options:0 + error:&error]; + if (error) { + NSLog(@"Error converting favorites data to plist format: %@", error); + goto end_cleanup; } NSFileManager *fileManager = [NSFileManager defaultManager]; @@ -424,9 +415,7 @@ static SPFavoritesController *sharedFavoritesController = nil; if (error) { NSLog(@"Error retrieving data directory path: %@", [error localizedDescription]); - - pthread_mutex_unlock(&writeLock); - return; + goto end_cleanup; } NSString *favoritesFile = [dataPath stringByAppendingPathComponent:SPFavoritesDataFile]; @@ -445,9 +434,7 @@ static SPFavoritesController *sharedFavoritesController = nil; // We can't move it so try and delete it if (![fileManager removeItemAtPath:favoritesFile error:&error] && error) { NSLog(@"Unable to delete existing favorites data file during save. Something is wrong, permissions perhaps: %@", [error localizedDescription]); - - pthread_mutex_unlock(&writeLock); - return; + goto end_cleanup; } } @@ -471,6 +458,7 @@ static SPFavoritesController *sharedFavoritesController = nil; [fileManager removeItemAtPath:favoritesBackupFile error:NULL]; } +end_cleanup: pthread_mutex_unlock(&writeLock); [pool release]; diff --git a/Source/SPFavoritesExporter.m b/Source/SPFavoritesExporter.m index d37ce07d..419a24c3 100644 --- a/Source/SPFavoritesExporter.m +++ b/Source/SPFavoritesExporter.m @@ -66,9 +66,6 @@ { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSError *error = nil; - NSString *errorString = nil; - NSMutableArray *favorites = [[NSMutableArray alloc] init]; // Get a dictionary representation of all favorites @@ -83,24 +80,24 @@ NSDictionary *dictionary = @{SPFavoritesDataRootKey : favorites}; [favorites release]; - + // Convert the current favorites tree to a dictionary representation to create the plist data - NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:dictionary + NSError *error = nil; + NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:dictionary format:NSPropertyListXMLFormat_v1_0 - errorDescription:&errorString]; + options:0 + error:&error]; - if (plistData) { + if (error) { + NSLog(@"Error converting favorites data to plist format: %@", error); + } + else if (plistData) { [plistData writeToFile:[self exportPath] options:NSAtomicWrite error:&error]; if (error) { - NSLog(@"Error writing favorites data: %@", [error localizedDescription]); + NSLog(@"Error writing favorites data: %@", error); } } - else if (errorString) { - NSLog(@"Error converting favorites data to plist format: %@", errorString); - - [errorString release]; - } [self _informDelegateOfExportCompletion:error]; diff --git a/Source/SPFieldEditorController.m b/Source/SPFieldEditorController.m index ba16da73..865816d7 100644 --- a/Source/SPFieldEditorController.m +++ b/Source/SPFieldEditorController.m @@ -123,17 +123,27 @@ typedef enum { // Load default QL types NSMutableArray *qlTypesItems = [[NSMutableArray alloc] init]; NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; - NSData *defaultTypeData = [NSData dataWithContentsOfFile:[NSBundle pathForResource:@"EditorQuickLookTypes.plist" ofType:nil inDirectory:[[NSBundle mainBundle] bundlePath]] - options:NSMappedRead error:&readError]; - - NSDictionary *defaultQLTypes = [NSPropertyListSerialization propertyListFromData:defaultTypeData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError]; - if(defaultQLTypes == nil || readError != nil || convError != nil) - NSLog(@"Error while reading 'EditorQuickLookTypes.plist':\n%@\n%@", [readError localizedDescription], convError); - if(defaultQLTypes != nil && [defaultQLTypes objectForKey:@"QuickLookTypes"]) { + NSString *filePath = [NSBundle pathForResource:@"EditorQuickLookTypes.plist" + ofType:nil + inDirectory:[[NSBundle mainBundle] bundlePath]]; + + NSData *defaultTypeData = [NSData dataWithContentsOfFile:filePath + options:NSMappedRead + error:&readError]; + + NSDictionary *defaultQLTypes = nil; + if(defaultTypeData && !readError) { + defaultQLTypes = [NSPropertyListSerialization propertyListWithData:defaultTypeData + options:NSPropertyListImmutable + format:NULL + error:&readError]; + } + + if(defaultQLTypes == nil || readError ) { + NSLog(@"Error while reading 'EditorQuickLookTypes.plist':\n%@", readError); + } + else if(defaultQLTypes != nil && [defaultQLTypes objectForKey:@"QuickLookTypes"]) { for(id type in [defaultQLTypes objectForKey:@"QuickLookTypes"]) { NSMenuItem *aMenuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithString:[type objectForKey:@"MenuLabel"]] action:NULL keyEquivalent:@""]; [aMenuItem setTag:tag]; diff --git a/Source/SPPreferencesUpgrade.m b/Source/SPPreferencesUpgrade.m index 11cd146c..9cd0d471 100644 --- a/Source/SPPreferencesUpgrade.m +++ b/Source/SPPreferencesUpgrade.m @@ -414,29 +414,26 @@ void SPMigrateConnectionFavoritesData(void) NSDictionary *newFavorites = @{SPFavoritesRootKey : [NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"Favorites", @"favorites label"), SPFavoritesGroupNameKey, favorites, SPFavoriteChildrenKey, nil]}; error = nil; - NSString *errorString = nil; - NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:newFavorites + NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:newFavorites format:NSPropertyListXMLFormat_v1_0 - errorDescription:&errorString]; - if (plistData) { + options:0 + error:&error]; + + if (error) { + NSLog(@"Error converting migrating favorites data to plist format: %@", error); + } + else if (plistData) { [plistData writeToFile:favoritesFile options:NSAtomicWrite error:&error]; if (error) { - NSLog(@"Error migrating favorites data: %@", [error localizedDescription]); + NSLog(@"Error migrating favorites data: %@", error); } else { [prefs removeObjectForKey:SPOldFavoritesKey]; } } - else if (errorString) { - NSLog(@"Error converting migrating favorites data to plist format: %@", errorString); - - [favorites release]; - [errorString release]; - return; - } - + [favorites release]; } diff --git a/Source/SPQueryController.m b/Source/SPQueryController.m index 87709949..7f48330d 100644 --- a/Source/SPQueryController.m +++ b/Source/SPQueryController.m @@ -703,24 +703,30 @@ static SPQueryController *sharedQueryController = nil; - (NSError *)loadCompletionLists { NSError *readError = nil; - NSString *convError = nil; NSString *errorDescription = nil; - - NSPropertyListFormat format; - NSData *completionTokensData = [NSData dataWithContentsOfFile: - [NSBundle pathForResource:SPCompletionTokensFilename - ofType:nil - inDirectory:[[NSBundle mainBundle] bundlePath]] - options:NSMappedRead error:&readError]; - - NSDictionary *completionPlist = [NSDictionary dictionaryWithDictionary: - [NSPropertyListSerialization propertyListFromData:completionTokensData - mutabilityOption:NSPropertyListMutableContainersAndLeaves - format:&format - errorDescription:&convError]]; - - if (completionPlist == nil || readError != nil || convError != nil) { - errorDescription = [NSString stringWithFormat:@"Error reading '%@': %@, %@", SPCompletionTokensFilename, [readError localizedDescription], convError]; + + NSString *filePath = [NSBundle pathForResource:SPCompletionTokensFilename + ofType:nil + inDirectory:[[NSBundle mainBundle] bundlePath]]; + + NSData *completionTokensData = [NSData dataWithContentsOfFile:filePath + options:NSMappedRead + error:&readError]; + + NSDictionary *completionPlist = nil; + if(completionTokensData && !readError) { + NSDictionary *plistDict = [NSPropertyListSerialization propertyListWithData:completionTokensData + options:NSPropertyListMutableContainersAndLeaves + format:NULL + error:&readError]; + + if(plistDict && !readError) { + completionPlist = [NSDictionary dictionaryWithDictionary:plistDict]; + } + } + + if (completionPlist == nil || readError) { + errorDescription = [NSString stringWithFormat:@"Error reading '%@': %@", SPCompletionTokensFilename, readError]; } else { if ([completionPlist objectForKey:SPCompletionTokensKeywordsKey]) { @@ -994,12 +1000,7 @@ static SPQueryController *sharedQueryController = nil; } // Inform all opened documents to update the history list - for (id doc in [SPAppDelegate orderedDocuments]) - { - if([[doc valueForKeyPath:@"customQueryInstance"] respondsToSelector:@selector(historyItemsHaveBeenUpdated:)]) { - [[doc valueForKeyPath:@"customQueryInstance"] performSelectorOnMainThread:@selector(historyItemsHaveBeenUpdated:) withObject:self waitUntilDone:NO]; - } - } + [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:SPHistoryItemsHaveBeenUpdatedNotification object:self]; // User did choose to clear the global history list if (![fileURL isFileURL] && ![historyArray count]) { diff --git a/Source/SPQueryFavoriteManager.h b/Source/SPQueryFavoriteManager.h index 0f0141bf..f1527b40 100644 --- a/Source/SPQueryFavoriteManager.h +++ b/Source/SPQueryFavoriteManager.h @@ -32,12 +32,6 @@ @class SPDatabaseDocument; @class SPSplitView; -@interface NSObject (SPQueryFavoriteManagerDelegate) - -- (void)queryFavoritesHaveBeenUpdated:(id)manager; - -@end - @interface SPQueryFavoriteManager : NSWindowController <NSOpenSavePanelDelegate> { #ifndef SP_CODA /* ivars */ diff --git a/Source/SPQueryFavoriteManager.m b/Source/SPQueryFavoriteManager.m index e987986b..2ab8ec82 100644 --- a/Source/SPQueryFavoriteManager.m +++ b/Source/SPQueryFavoriteManager.m @@ -199,11 +199,19 @@ [[self window] makeFirstResponder:favoriteNameTextField]; // Duplicate a selected favorite if sender == self - if (sender == self) - favorite = [NSMutableDictionary dictionaryWithObjects:[NSArray arrayWithObjects:[[favoriteNameTextField stringValue] stringByAppendingFormat:@" Copy"], [favoriteQueryTextView string], nil] forKeys:[NSArray arrayWithObjects:@"name", @"query", nil]]; + if (sender == self) { + favorite = [NSMutableDictionary dictionaryWithDictionary:@{ + @"name": [NSString stringWithFormat:NSLocalizedString(@"%@ Copy", @"query favorite manager : duplicate favorite : new favorite name"),[favoriteNameTextField stringValue]], + @"query": [NSString stringWithString:[favoriteQueryTextView string]] // #2938 - without copying the string we would store the live NS*MutableString object that backs the text view and changes its contents when selection changes! + }]; + } // Add a new favorite - else - favorite = [NSMutableDictionary dictionaryWithObjects:@[@"New Favorite", @""] forKeys:@[@"name", @"query"]]; + else { + favorite = [NSMutableDictionary dictionaryWithDictionary:@{ + @"name": NSLocalizedString(@"New Favorite",@"query favorite manager : new favorite : name"), + @"query": @"" + }]; + } // If a favourite is currently selected, add the new favourite next to it if ([favoritesTableView numberOfSelectedRows] > 0) { @@ -476,10 +484,7 @@ [prefs setObject:[self queryFavoritesForFileURL:nil] forKey:SPQueryFavorites]; // Inform all opened documents to update the query favorites list -#warning This should be done using notifications - for(id doc in [SPAppDelegate orderedDocuments]) - if([[doc valueForKeyPath:@"customQueryInstance"] respondsToSelector:@selector(queryFavoritesHaveBeenUpdated:)]) - [[doc valueForKeyPath:@"customQueryInstance"] queryFavoritesHaveBeenUpdated:self]; + [[NSNotificationCenter defaultCenter] postNotificationName:SPQueryFavoritesHaveBeenUpdatedNotification object:self]; } #endif @@ -814,8 +819,6 @@ NSString *filename = [[[panel URLs] objectAtIndex:0] path]; NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; NSInteger insertionIndexStart, insertionIndexEnd; NSDictionary *spf = nil; @@ -823,15 +826,19 @@ if([[[filename pathExtension] lowercaseString] isEqualToString:SPFileExtensionDefault]) { NSData *pData = [NSData dataWithContentsOfFile:filename options:NSUncachedRead error:&readError]; - spf = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; - - if(!spf || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithString:NSLocalizedString(@"Error while reading data file", @"error while reading data file")] + if(pData && !readError) { + spf = [[NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&readError] retain]; + } + + if(!spf || readError) { + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while reading data file", @"error while reading data file") defaultButton:NSLocalizedString(@"OK", @"OK button") alternateButton:nil - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"File couldn't be read.", @"error while reading data file")]; + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"File couldn't be read. (%@)", @"error while reading data file"), [readError localizedDescription]]; [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; @@ -924,24 +931,25 @@ [spfdata setObject:favoriteData forKey:SPQueryFavorites]; - NSString *err = nil; - NSData *plist = [NSPropertyListSerialization dataFromPropertyList:spfdata - format:NSPropertyListXMLFormat_v1_0 - errorDescription:&err]; + NSError *error = nil; + + NSData *plist = [NSPropertyListSerialization dataWithPropertyList:spfdata + format:NSPropertyListXMLFormat_v1_0 + options:0 + error:&error]; - if(err != nil) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithString:NSLocalizedString(@"Error while converting query favorite data", @"error while converting query favorite data")] + if(error) { + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while converting query favorite data", @"error while converting query favorite data") defaultButton:NSLocalizedString(@"OK", @"OK button") alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"%@", err]; + otherButton:nil + informativeTextWithFormat:@"%@", [error localizedDescription]]; [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; return; } - NSError *error = nil; [plist writeToURL:[panel URL] options:NSAtomicWrite error:&error]; if (error) [[NSAlert alertWithError:error] runModal]; diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m index aa614b76..16f5ac99 100644 --- a/Source/SPTableContent.m +++ b/Source/SPTableContent.m @@ -73,6 +73,7 @@ static NSString *SPTableFilterSetDefaultOperator = @"SPTableFilterSetDefaultOper - (BOOL)cancelRowEditing; - (void)documentWillClose:(NSNotification *)notification; +- (void)contentFiltersHaveBeenUpdated:(NSNotification *)notification; #pragma mark - SPTableContentDataSource_Private_API @@ -175,21 +176,28 @@ static NSString *SPTableFilterSetDefaultOperator = @"SPTableFilterSetDefaultOper whiteColor = [NSColor whiteColor]; // Init default filters for Content Browser - contentFilters = nil; contentFilters = [[NSMutableDictionary alloc] init]; numberOfDefaultFilters = [[NSMutableDictionary alloc] init]; NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; - NSData *defaultFilterData = [NSData dataWithContentsOfFile:[NSBundle pathForResource:@"ContentFilters.plist" ofType:nil inDirectory:[[NSBundle mainBundle] bundlePath]] - options:NSMappedRead error:&readError]; - - [contentFilters setDictionary:[NSPropertyListSerialization propertyListFromData:defaultFilterData - mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&convError]]; + NSString *filePath = [NSBundle pathForResource:@"ContentFilters.plist" ofType:nil inDirectory:[[NSBundle mainBundle] bundlePath]]; + NSData *defaultFilterData = [NSData dataWithContentsOfFile:filePath + options:NSMappedRead + error:&readError]; + + if(defaultFilterData && !readError) { + NSDictionary *defaultFilterDict = [NSPropertyListSerialization propertyListWithData:defaultFilterData + options:NSPropertyListMutableContainersAndLeaves + format:NULL + error:&readError]; + + if(defaultFilterDict && !readError) { + [contentFilters setDictionary:defaultFilterDict]; + } + } - if (contentFilters == nil || readError != nil || convError != nil) { - NSLog(@"Error while reading 'ContentFilters.plist':\n%@\n%@", [readError localizedDescription], convError); + if (readError) { + NSLog(@"Error while reading 'ContentFilters.plist':\n%@", readError); NSBeep(); } else { @@ -292,6 +300,10 @@ static NSString *SPTableFilterSetDefaultOperator = @"SPTableFilterSetDefaultOper selector:@selector(documentWillClose:) name:SPDocumentWillCloseNotification object:tableDocumentInstance]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(contentFiltersHaveBeenUpdated:) + name:SPContentFiltersHaveBeenUpdatedNotification + object:nil]; } #pragma mark - @@ -2582,6 +2594,11 @@ static NSString *SPTableFilterSetDefaultOperator = @"SPTableFilterSetDefaultOper [linkPool drain]; } +- (void)contentFiltersHaveBeenUpdated:(NSNotification *)notification +{ + [self setCompareTypes:nil]; +} + /** * Sets the compare types for the filter and the appropriate formatter for the textField */ diff --git a/Source/SPTextView.m b/Source/SPTextView.m index cb27b8da..de1ddc04 100644 --- a/Source/SPTextView.m +++ b/Source/SPTextView.m @@ -83,6 +83,7 @@ NSInteger _alphabeticSort(id string1, id string2, void *reverse); #ifndef SP_CODA +- (void)_setTextSelectionColor:(NSColor *)newSelectionColor; - (void)_setTextSelectionColor:(NSColor *)newSelectionColor onBackgroundColor:(NSColor *)aBackgroundColor; #endif - (void)_positionCompletionPopup:(SPNarrowDownCompletion *)aPopup relativeToTextAtLocation:(NSUInteger)aLocation; @@ -183,27 +184,56 @@ static inline NSPoint SPPointOnLine(NSPoint a, NSPoint b, CGFloat t) { return NS [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(boundsDidChangeNotification:) name:NSViewBoundsDidChangeNotification object:[scrollView contentView]]; #ifndef SP_CODA - [self setQueryHiliteColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorHighlightQueryColor]]]; - NSColor *backgroundColor = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorBackgroundColor]]; - [self setQueryEditorBackgroundColor:backgroundColor]; - [self setBackgroundColor:backgroundColor]; - [self setCommentColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorCommentColor]]]; - [self setQuoteColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorQuoteColor]]]; - [self setKeywordColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorSQLKeywordColor]]]; - [self setBacktickColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorBacktickColor]]]; - [self setNumericColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorNumericColor]]]; - [self setVariableColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorVariableColor]]]; - [self setOtherTextColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorTextColor]]]; - [self setTextColor:otherTextColor]; - [self setInsertionPointColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorCaretColor]]]; + { + struct csItem { + NSString *p; + SEL m; + } colorSetup[] = { + { .p = SPCustomQueryEditorHighlightQueryColor, .m = @selector(setQueryHiliteColor:) }, + { .p = SPCustomQueryEditorBackgroundColor, .m = @selector(setQueryEditorBackgroundColor:) }, + { .p = SPCustomQueryEditorBackgroundColor, .m = @selector(setBackgroundColor:) }, + { .p = SPCustomQueryEditorCommentColor, .m = @selector(setCommentColor:) }, + { .p = SPCustomQueryEditorQuoteColor, .m = @selector(setQuoteColor:) }, + { .p = SPCustomQueryEditorSQLKeywordColor, .m = @selector(setKeywordColor:) }, + { .p = SPCustomQueryEditorBacktickColor, .m = @selector(setBacktickColor:) }, + { .p = SPCustomQueryEditorNumericColor, .m = @selector(setNumericColor:) }, + { .p = SPCustomQueryEditorVariableColor, .m = @selector(setVariableColor:) }, + { .p = SPCustomQueryEditorTextColor, .m = @selector(setOtherTextColor:) }, + { .p = SPCustomQueryEditorTextColor, .m = @selector(setTextColor:) }, + { .p = SPCustomQueryEditorCaretColor, .m = @selector(setInsertionPointColor:) }, + { .p = SPCustomQueryEditorSelectionColor, .m = @selector(_setTextSelectionColor:) }, + { .p = nil, .m = NULL } // stop key + }; + + struct csItem *item = &colorSetup[0]; + + NSDictionary *vendorDefaults = [prefs volatileDomainForName:NSRegistrationDomain]; //prefs from -registerDefaults: in app controller + + do { + NSData *colorData = [prefs dataForKey:item->p]; + NSColor *color; + BOOL canRetry = YES; +retry: + if(colorData && (color = [NSUnarchiver unarchiveObjectWithData:colorData])) { + [self performSelector:item->m withObject:color]; + } + else if(canRetry) { + // #2963: previous versions of SP would accept invalid data (resulting in `nil`) and store it in prefs, + // so if loading failed use the default color instead (`nil` would cause exceptions later on) + colorData = [vendorDefaults objectForKey:item->p]; + canRetry = NO; + SPLog(@"user defaults contains invalid value for theme color '%@'! (retrying with default value)", item->p); + goto retry; + } + } while((++item)->p); + } + [self setShouldHiliteQuery:[prefs boolForKey:SPCustomQueryHighlightCurrentQuery]]; - [self _setTextSelectionColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorSelectionColor]] onBackgroundColor:backgroundColor]; - [self setAutomaticDashSubstitutionEnabled:NO]; // prevents -- from becoming —, the em dash. [self setAutomaticQuoteSubstitutionEnabled:NO]; // prevents ' and " from becoming ‘, ’ and “, ” respectively. - // Register observers for the when editor background colors preference changes + // Register observers for the when editor colors preference changes [prefs addObserver:self forKeyPath:SPCustomQueryEditorSelectionColor options:NSKeyValueObservingOptionNew context:NULL]; [prefs addObserver:self forKeyPath:SPCustomQueryEditorCaretColor options:NSKeyValueObservingOptionNew context:NULL]; [prefs addObserver:self forKeyPath:SPCustomQueryEditorFont options:NSKeyValueObservingOptionNew context:NULL]; @@ -3730,6 +3760,11 @@ NSInteger _alphabeticSort(id string1, id string2, void *reverse) // Set the selection colour [self setSelectedTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:newSelectionColor, NSBackgroundColorAttributeName, nil]]; } + +- (void)_setTextSelectionColor:(NSColor *)newSelectionColor +{ + [self _setTextSelectionColor:newSelectionColor onBackgroundColor:[self backgroundColor]]; +} #endif /** diff --git a/Source/SPTextViewAdditions.m b/Source/SPTextViewAdditions.m index a81dcd4d..2a322748 100644 --- a/Source/SPTextViewAdditions.m +++ b/Source/SPTextViewAdditions.m @@ -524,269 +524,272 @@ return; } - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; NSDictionary *cmdData = nil; - NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&readError]; + { + NSError *error = nil; - cmdData = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; + NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&error]; - if(!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSLog(@"“%@” file couldn't be read.", infoPath); - NSBeep(); - if (cmdData) [cmdData release]; - return; - } else { - if([cmdData objectForKey:SPBundleFileCommandKey] && [(NSString *)[cmdData objectForKey:SPBundleFileCommandKey] length]) { + if(!error) { + cmdData = [[NSPropertyListSerialization propertyListWithData:pData + options:NSPropertyListImmutable + format:NULL + error:&error] retain]; + } + + if(!cmdData || error) { + NSLog(@"“%@” file couldn't be read. (readError=%@)", infoPath, error); + NSBeep(); + if (cmdData) [cmdData release]; + return; + } + } + + if([cmdData objectForKey:SPBundleFileCommandKey] && [(NSString *)[cmdData objectForKey:SPBundleFileCommandKey] length]) { - NSString *cmd = [cmdData objectForKey:SPBundleFileCommandKey]; - NSString *inputAction = @""; - NSString *inputFallBackAction = @""; - NSError *err = nil; - NSString *uuid = [NSString stringWithNewUUID]; - NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, uuid]; + NSString *cmd = [cmdData objectForKey:SPBundleFileCommandKey]; + NSString *inputAction = @""; + NSString *inputFallBackAction = @""; + NSError *err = nil; + NSString *uuid = [NSString stringWithNewUUID]; + NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, uuid]; - NSRange currentWordRange, currentSelectionRange, currentLineRange, currentQueryRange; + NSRange currentWordRange, currentSelectionRange, currentLineRange, currentQueryRange; - [[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil]; + [[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil]; - BOOL selfIsQueryEditor = ([[[self class] description] isEqualToString:@"SPTextView"] && [[self delegate] respondsToSelector:@selector(currentQueryRange)]); + BOOL selfIsQueryEditor = ([[[self class] description] isEqualToString:@"SPTextView"] && [[self delegate] respondsToSelector:@selector(currentQueryRange)]); - if([cmdData objectForKey:SPBundleFileInputSourceKey]) - inputAction = [[cmdData objectForKey:SPBundleFileInputSourceKey] lowercaseString]; - if([cmdData objectForKey:SPBundleFileInputSourceFallBackKey]) - inputFallBackAction = [[cmdData objectForKey:SPBundleFileInputSourceFallBackKey] lowercaseString]; + if([cmdData objectForKey:SPBundleFileInputSourceKey]) + inputAction = [[cmdData objectForKey:SPBundleFileInputSourceKey] lowercaseString]; + if([cmdData objectForKey:SPBundleFileInputSourceFallBackKey]) + inputFallBackAction = [[cmdData objectForKey:SPBundleFileInputSourceFallBackKey] lowercaseString]; - currentSelectionRange = [self selectedRange]; - currentWordRange = [self getRangeForCurrentWord]; - currentLineRange = [[self string] lineRangeForRange:NSMakeRange([self selectedRange].location, 0)]; + currentSelectionRange = [self selectedRange]; + currentWordRange = [self getRangeForCurrentWord]; + currentLineRange = [[self string] lineRangeForRange:NSMakeRange([self selectedRange].location, 0)]; - if(selfIsQueryEditor) { - currentQueryRange = [(SPCustomQuery*)[self delegate] currentQueryRange]; + if(selfIsQueryEditor) { + currentQueryRange = [(SPCustomQuery*)[self delegate] currentQueryRange]; + } else { + currentQueryRange = currentLineRange; + } + if(!currentQueryRange.length) + currentQueryRange = currentSelectionRange; + + NSRange replaceRange = currentSelectionRange; + if([inputAction isEqualToString:SPBundleInputSourceSelectedText]) { + if(!currentSelectionRange.length) { + if([inputFallBackAction isEqualToString:SPBundleInputSourceCurrentWord]) + replaceRange = currentWordRange; + else if([inputFallBackAction isEqualToString:SPBundleInputSourceCurrentLine]) + replaceRange = currentLineRange; + else if([inputFallBackAction isEqualToString:SPBundleInputSourceCurrentQuery]) + replaceRange = currentQueryRange; + else if([inputFallBackAction isEqualToString:SPBundleInputSourceEntireContent]) + replaceRange = NSMakeRange(0,[[self string] length]); } else { - currentQueryRange = currentLineRange; + replaceRange = currentSelectionRange; } - if(!currentQueryRange.length) - currentQueryRange = currentSelectionRange; - - NSRange replaceRange = currentSelectionRange; - if([inputAction isEqualToString:SPBundleInputSourceSelectedText]) { - if(!currentSelectionRange.length) { - if([inputFallBackAction isEqualToString:SPBundleInputSourceCurrentWord]) - replaceRange = currentWordRange; - else if([inputFallBackAction isEqualToString:SPBundleInputSourceCurrentLine]) - replaceRange = currentLineRange; - else if([inputFallBackAction isEqualToString:SPBundleInputSourceCurrentQuery]) - replaceRange = currentQueryRange; - else if([inputFallBackAction isEqualToString:SPBundleInputSourceEntireContent]) - replaceRange = NSMakeRange(0,[[self string] length]); - } else { - replaceRange = currentSelectionRange; - } - } - else if([inputAction isEqualToString:SPBundleInputSourceEntireContent]) { - replaceRange = NSMakeRange(0, [[self string] length]); - } + } + else if([inputAction isEqualToString:SPBundleInputSourceEntireContent]) { + replaceRange = NSMakeRange(0, [[self string] length]); + } - NSMutableDictionary *env = [NSMutableDictionary dictionary]; - [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:SPBundleShellVariableBundlePath]; - [env setObject:bundleInputFilePath forKey:SPBundleShellVariableInputFilePath]; - [env setObject:SPBundleScopeInputField forKey:SPBundleShellVariableBundleScope]; - - id tableSource = [self delegate]; - if([[[tableSource class] description] isEqualToString:@"SPFieldEditorController"]) { - NSDictionary *editedFieldInfo = [tableSource editedFieldInfo]; - [env setObject:[editedFieldInfo objectForKey:@"colName"] forKey:SPBundleShellVariableCurrentEditedColumnName]; - if([editedFieldInfo objectForKey:@"tableName"]) - [env setObject:[editedFieldInfo objectForKey:@"tableName"] forKey:SPBundleShellVariableCurrentEditedTable]; - [env setObject:[editedFieldInfo objectForKey:@"usedQuery"] forKey:SPBundleShellVariableUsedQueryForTable]; - [env setObject:[editedFieldInfo objectForKey:@"tableSource"] forKey:SPBundleShellVariableDataTableSource]; - } - else if([[[tableSource class] description] isEqualToString:@"SPCopyTable"]) { - NSInteger editedCol = [tableSource editedColumn]; - if(editedCol > -1) { - NSString *colName = [[[[tableSource tableColumns] objectAtIndex:editedCol] headerCell] stringValue]; - if([[[[tableSource dataSource] class] description] hasSuffix:@"Content"]) { - [env setObject:[colName description] forKey:SPBundleShellVariableCurrentEditedColumnName]; - [env setObject:@"content" forKey:SPBundleShellVariableDataTableSource]; - } else { - NSArray *defs = [[tableSource delegate] dataColumnDefinitions]; - for(NSDictionary* col in defs) { - if([[col objectForKey:@"name"] isEqualToString:colName]) { - [env setObject:[col objectForKey:@"org_name"] forKey:SPBundleShellVariableCurrentEditedColumnName]; - [env setObject:[col objectForKey:@"org_table"] forKey:SPBundleShellVariableCurrentEditedTable]; - break; - } + NSMutableDictionary *env = [NSMutableDictionary dictionary]; + [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:SPBundleShellVariableBundlePath]; + [env setObject:bundleInputFilePath forKey:SPBundleShellVariableInputFilePath]; + [env setObject:SPBundleScopeInputField forKey:SPBundleShellVariableBundleScope]; + + id tableSource = [self delegate]; + if([[[tableSource class] description] isEqualToString:@"SPFieldEditorController"]) { + NSDictionary *editedFieldInfo = [tableSource editedFieldInfo]; + [env setObject:[editedFieldInfo objectForKey:@"colName"] forKey:SPBundleShellVariableCurrentEditedColumnName]; + if([editedFieldInfo objectForKey:@"tableName"]) + [env setObject:[editedFieldInfo objectForKey:@"tableName"] forKey:SPBundleShellVariableCurrentEditedTable]; + [env setObject:[editedFieldInfo objectForKey:@"usedQuery"] forKey:SPBundleShellVariableUsedQueryForTable]; + [env setObject:[editedFieldInfo objectForKey:@"tableSource"] forKey:SPBundleShellVariableDataTableSource]; + } + else if([[[tableSource class] description] isEqualToString:@"SPCopyTable"]) { + NSInteger editedCol = [tableSource editedColumn]; + if(editedCol > -1) { + NSString *colName = [[[[tableSource tableColumns] objectAtIndex:editedCol] headerCell] stringValue]; + if([[[[tableSource dataSource] class] description] hasSuffix:@"Content"]) { + [env setObject:[colName description] forKey:SPBundleShellVariableCurrentEditedColumnName]; + [env setObject:@"content" forKey:SPBundleShellVariableDataTableSource]; + } else { + NSArray *defs = [[tableSource delegate] dataColumnDefinitions]; + for(NSDictionary* col in defs) { + if([[col objectForKey:@"name"] isEqualToString:colName]) { + [env setObject:[col objectForKey:@"org_name"] forKey:SPBundleShellVariableCurrentEditedColumnName]; + [env setObject:[col objectForKey:@"org_table"] forKey:SPBundleShellVariableCurrentEditedTable]; + break; } - [env setObject:@"query" forKey:SPBundleShellVariableDataTableSource]; } - if([[tableSource delegate] respondsToSelector:@selector(usedQuery)] && [[tableSource delegate] usedQuery]) - [env setObject:[[tableSource delegate] usedQuery] forKey:SPBundleShellVariableUsedQueryForTable]; + [env setObject:@"query" forKey:SPBundleShellVariableDataTableSource]; } + if([[tableSource delegate] respondsToSelector:@selector(usedQuery)] && [[tableSource delegate] usedQuery]) + [env setObject:[[tableSource delegate] usedQuery] forKey:SPBundleShellVariableUsedQueryForTable]; } + } - if(selfIsQueryEditor && [(SPCustomQuery*)[self delegate] currentQueryRange].length) - [env setObject:[[self string] substringWithRange:[(SPCustomQuery*)[self delegate] currentQueryRange]] forKey:SPBundleShellVariableCurrentQuery]; + if(selfIsQueryEditor && [(SPCustomQuery*)[self delegate] currentQueryRange].length) + [env setObject:[[self string] substringWithRange:[(SPCustomQuery*)[self delegate] currentQueryRange]] forKey:SPBundleShellVariableCurrentQuery]; - if(currentSelectionRange.length) - [env setObject:[[self string] substringWithRange:currentSelectionRange] forKey:SPBundleShellVariableSelectedText]; + if(currentSelectionRange.length) + [env setObject:[[self string] substringWithRange:currentSelectionRange] forKey:SPBundleShellVariableSelectedText]; - if(currentWordRange.length) - [env setObject:[[self string] substringWithRange:currentWordRange] forKey:SPBundleShellVariableCurrentWord]; + if(currentWordRange.length) + [env setObject:[[self string] substringWithRange:currentWordRange] forKey:SPBundleShellVariableCurrentWord]; - if(currentLineRange.length) - [env setObject:[[self string] substringWithRange:currentLineRange] forKey:SPBundleShellVariableCurrentLine]; + if(currentLineRange.length) + [env setObject:[[self string] substringWithRange:currentLineRange] forKey:SPBundleShellVariableCurrentLine]; - [env setObject:NSStringFromRange(replaceRange) forKey:SPBundleShellVariableSelectedTextRange]; + [env setObject:NSStringFromRange(replaceRange) forKey:SPBundleShellVariableSelectedTextRange]; - NSError *inputFileError = nil; - NSString *input = [NSString stringWithString:[[self string] substringWithRange:replaceRange]]; + NSError *inputFileError = nil; + NSString *input = [NSString stringWithString:[[self string] substringWithRange:replaceRange]]; - [input writeToFile:bundleInputFilePath - atomically:YES - encoding:NSUTF8StringEncoding - error:&inputFileError]; + [input writeToFile:bundleInputFilePath + atomically:YES + encoding:NSUTF8StringEncoding + error:&inputFileError]; - if(inputFileError != nil) { - NSString *errorMessage = [inputFileError localizedDescription]; - SPOnewayAlertSheet( - NSLocalizedString(@"Bundle Error", @"bundle error"), - [self window], - [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] - ); - if (cmdData) [cmdData release]; - return; - } + if(inputFileError != nil) { + NSString *errorMessage = [inputFileError localizedDescription]; + SPOnewayAlertSheet( + NSLocalizedString(@"Bundle Error", @"bundle error"), + [self window], + [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] + ); + if (cmdData) [cmdData release]; + return; + } - NSString *output = [SPBundleCommandRunner runBashCommand:cmd withEnvironment:env - atCurrentDirectoryPath:nil - callerInstance:[SPAppDelegate frontDocument] - 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 = SPBundleOutputActionNone; - if([cmdData objectForKey:SPBundleFileOutputActionKey] && [(NSString *)[cmdData objectForKey:SPBundleFileOutputActionKey] length]) - 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; - } + NSString *output = [SPBundleCommandRunner runBashCommand:cmd withEnvironment:env + atCurrentDirectoryPath:nil + callerInstance:[SPAppDelegate frontDocument] + 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 = SPBundleOutputActionNone; + if([cmdData objectForKey:SPBundleFileOutputActionKey] && [(NSString *)[cmdData objectForKey:SPBundleFileOutputActionKey] length]) + 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(![action isEqualToString:SPBundleOutputActionNone]) { + if(err == nil && output) { + if(![action isEqualToString:SPBundleOutputActionNone]) { - if([action isEqualToString:SPBundleOutputActionShowAsTextTooltip]) { - [SPTooltip showWithObject:output]; - } + if([action isEqualToString:SPBundleOutputActionShowAsTextTooltip]) { + [SPTooltip showWithObject:output]; + } - else if([action isEqualToString:SPBundleOutputActionShowAsHTMLTooltip]) { - [SPTooltip showWithObject:output ofType:@"html"]; - } + else if([action isEqualToString:SPBundleOutputActionShowAsHTMLTooltip]) { + [SPTooltip showWithObject:output ofType:@"html"]; + } - else if([action isEqualToString:SPBundleOutputActionShowAsHTML]) { - BOOL correspondingWindowFound = NO; - for(id win in [NSApp windows]) { - if([[win delegate] isKindOfClass:[SPBundleHTMLOutputController class]]) { - if([[[win delegate] windowUUID] isEqualToString:[cmdData objectForKey:SPBundleFileUUIDKey]]) { - correspondingWindowFound = YES; - [[win delegate] displayHTMLContent:output withOptions:nil]; - break; - } + else if([action isEqualToString:SPBundleOutputActionShowAsHTML]) { + BOOL correspondingWindowFound = NO; + for(id win in [NSApp windows]) { + if([[win delegate] isKindOfClass:[SPBundleHTMLOutputController class]]) { + if([[[win delegate] windowUUID] isEqualToString:[cmdData objectForKey:SPBundleFileUUIDKey]]) { + correspondingWindowFound = YES; + [[win delegate] displayHTMLContent:output withOptions:nil]; + break; } } - if(!correspondingWindowFound) { - SPBundleHTMLOutputController *c = [[SPBundleHTMLOutputController alloc] init]; - [c setWindowUUID:[cmdData objectForKey:SPBundleFileUUIDKey]]; - [c displayHTMLContent:output withOptions:nil]; - [SPAppDelegate addHTMLOutputController:c]; - } } + if(!correspondingWindowFound) { + SPBundleHTMLOutputController *c = [[SPBundleHTMLOutputController alloc] init]; + [c setWindowUUID:[cmdData objectForKey:SPBundleFileUUIDKey]]; + [c displayHTMLContent:output withOptions:nil]; + [SPAppDelegate addHTMLOutputController:c]; + } + } - if([self isEditable]) { - - if([action isEqualToString:SPBundleOutputActionInsertAsText]) { - [self insertText:output]; - } + if([self isEditable]) { - else if([action isEqualToString:SPBundleOutputActionInsertAsSnippet]) { - if([self respondsToSelector:@selector(insertAsSnippet:atRange:)]) - [(SPTextView *)self insertAsSnippet:output atRange:replaceRange]; - else - [SPTooltip showWithObject:NSLocalizedString(@"Input Field doesn't support insertion of snippets.", @"input field doesn't support insertion of snippets.")]; - } + if([action isEqualToString:SPBundleOutputActionInsertAsText]) { + [self insertText:output]; + } - else if([action isEqualToString:SPBundleOutputActionReplaceContent]) { - if([[self string] length]) - [self setSelectedRange:NSMakeRange(0, [[self string] length])]; - [self insertText:output]; - } + else if([action isEqualToString:SPBundleOutputActionInsertAsSnippet]) { + if([self respondsToSelector:@selector(insertAsSnippet:atRange:)]) + [(SPTextView *)self insertAsSnippet:output atRange:replaceRange]; + else + [SPTooltip showWithObject:NSLocalizedString(@"Input Field doesn't support insertion of snippets.", @"input field doesn't support insertion of snippets.")]; + } - else if([action isEqualToString:SPBundleOutputActionReplaceSelection]) { - NSRange safeRange = NSIntersectionRange(replaceRange, NSMakeRange(0, [[self string] length])); - [self shouldChangeTextInRange:safeRange replacementString:output]; - [self replaceCharactersInRange:safeRange withString:output]; - } + else if([action isEqualToString:SPBundleOutputActionReplaceContent]) { + if([[self string] length]) + [self setSelectedRange:NSMakeRange(0, [[self string] length])]; + [self insertText:output]; + } - } else { - [SPTooltip showWithObject:NSLocalizedString(@"Input Field is not editable.", @"input field is not editable.")]; + else if([action isEqualToString:SPBundleOutputActionReplaceSelection]) { + NSRange safeRange = NSIntersectionRange(replaceRange, NSMakeRange(0, [[self string] length])); + [self shouldChangeTextInRange:safeRange replacementString:output]; + [self replaceCharactersInRange:safeRange withString:output]; } + } else { + [SPTooltip showWithObject:NSLocalizedString(@"Input Field is not editable.", @"input field is not editable.")]; } - } else if([err code] != 9) { // Suppress an error message if command was killed - NSString *errorMessage = [err localizedDescription]; - SPOnewayAlertSheet( - NSLocalizedString(@"BASH Error", @"bash error"), - [self window], - [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] - ); - } + } + } else if([err code] != 9) { // Suppress an error message if command was killed + NSString *errorMessage = [err localizedDescription]; + SPOnewayAlertSheet( + NSLocalizedString(@"BASH Error", @"bash error"), + [self window], + [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage] + ); } - if (cmdData) [cmdData release]; - } + if (cmdData) [cmdData release]; } /** |