From 3f11234f767748cefc04ec42de6008954359b19d Mon Sep 17 00:00:00 2001 From: Bibiko Date: Thu, 18 Nov 2010 23:57:50 +0000 Subject: =?UTF-8?q?=E2=80=A2=C2=A0further=20work=20on=20Bundle=20Editor=20?= =?UTF-8?q?=E2=80=A2=20generalised=20[NSString=20runBashCommand...]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/SPAppController.m | 4 +- Source/SPBundleEditorController.h | 2 + Source/SPBundleEditorController.m | 228 +++++++++++++++++++++++++++++++------- Source/SPConstants.h | 1 + Source/SPConstants.m | 1 + Source/SPStringAdditions.m | 34 +++--- 6 files changed, 208 insertions(+), 62 deletions(-) (limited to 'Source') diff --git a/Source/SPAppController.m b/Source/SPAppController.m index 430587a0..2003a9e6 100644 --- a/Source/SPAppController.m +++ b/Source/SPAppController.m @@ -893,7 +893,7 @@ NSBeep(); if (cmdData) [cmdData release]; } else { - if([cmdData objectForKey:SPBundleFileNameKey] && [[cmdData objectForKey:SPBundleFileNameKey] length] && [cmdData objectForKey:SPBundleFileScopeKey]) + if((![cmdData objectForKey:SPBundleFileDisabledKey] || ![[cmdData objectForKey:SPBundleFileDisabledKey] intValue]) && [cmdData objectForKey:SPBundleFileNameKey] && [[cmdData objectForKey:SPBundleFileNameKey] length] && [cmdData objectForKey:SPBundleFileScopeKey]) { NSArray *scopes = [[cmdData objectForKey:SPBundleFileScopeKey] componentsSeparatedByString:@" "]; @@ -924,7 +924,7 @@ mask = mask | NSCommandKeyMask; if([theMods rangeOfString:@"~"].length) mask = mask | NSAlternateKeyMask; - if(![[theChar lowercaseString] isEqualToString:theChar]) + if([theMods rangeOfString:@"$"].length) mask = mask | NSShiftKeyMask; for(NSString* scope in scopes) [[bundleKeyEquivalents objectForKey:scope] setObject:[NSArray arrayWithObjects:[theChar lowercaseString], diff --git a/Source/SPBundleEditorController.h b/Source/SPBundleEditorController.h index 35a11ed6..90ed03f1 100644 --- a/Source/SPBundleEditorController.h +++ b/Source/SPBundleEditorController.h @@ -23,6 +23,7 @@ // More info at #import +#import @class SRRecorderControl; @@ -84,6 +85,7 @@ - (IBAction)addCommandBundle:(id)sender; - (IBAction)removeCommandBundle:(id)sender; - (IBAction)revealCommandBundleInFinder:(id)sender; +- (IBAction)saveBundle:(id)sender; - (IBAction)showHelp:(id)sender; - (IBAction)saveAndCloseWindow:(id)sender; diff --git a/Source/SPBundleEditorController.m b/Source/SPBundleEditorController.m index b7e31aee..21cedc6e 100644 --- a/Source/SPBundleEditorController.m +++ b/Source/SPBundleEditorController.m @@ -24,12 +24,15 @@ #import "SPBundleEditorController.h" + @interface SPBundleEditorController (PrivateAPI) - (void)_updateInputPopupButton; @end +#pragma mark - + @implementation SPBundleEditorController /** @@ -82,6 +85,7 @@ - (void)awakeFromNib { + // Init all needed menus inputEditorScopePopUpMenu = [[NSMenu alloc] initWithTitle:@""]; inputInputFieldScopePopUpMenu = [[NSMenu alloc] initWithTitle:@""]; inputDataTableScopePopUpMenu = [[NSMenu alloc] initWithTitle:@""]; @@ -199,11 +203,12 @@ [inputNonePopUpMenu addItem:anItem]; [anItem release]; + [keyEquivalentField setCanCaptureGlobalHotKeys:YES]; + } #pragma mark - - - (IBAction)inputPopupButtonChanged:(id)sender { @@ -349,7 +354,8 @@ [removeButton setEnabled:([commandsTableView numberOfSelectedRows] > 0)]; [[self window] makeFirstResponder:commandsTableView]; - + if([commandsTableView numberOfSelectedRows] > 0) + [commandsTableView editColumn:0 row:insertIndex withEvent:nil select:YES]; } - (IBAction)removeCommandBundle:(id)sender @@ -358,7 +364,7 @@ defaultButton:NSLocalizedString(@"Remove", @"remove button") alternateButton:NSLocalizedString(@"Cancel", @"cancel button") otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"Are you sure you want to remove all selected Bundles? This action cannot be undone.", @"remove all selected bundles informative message")]; + informativeTextWithFormat:NSLocalizedString(@"Are you sure you want to move all selected Bundles to the Trash and remove them respectively?", @"move to trash and remove resp all selected bundles informative message")]; [alert setAlertStyle:NSCriticalAlertStyle]; @@ -370,13 +376,31 @@ [[buttons objectAtIndex:1] setKeyEquivalent:@"\r"]; [alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"removeSelectedBundles"]; + } - (IBAction)revealCommandBundleInFinder:(id)sender { + if([commandsTableView numberOfSelectedRows] != 1) return; + [[NSWorkspace sharedWorkspace] selectFile:[NSString stringWithFormat:@"%@/%@.%@/%@", bundlePath, [[commandBundleArray objectAtIndex:[commandsTableView selectedRow]] objectForKey:@"bundleName"], SPUserBundleFileExtension, SPBundleFileName] inFileViewerRootedAtPath:nil]; + +} + +- (IBAction)saveBundle:(id)sender +{ + NSSavePanel *panel = [NSSavePanel savePanel]; + + [panel setRequiredFileType:SPUserBundleFileExtension]; + + [panel setExtensionHidden:NO]; + [panel setAllowsOtherFileTypes:NO]; + [panel setCanSelectHiddenExtension:YES]; + [panel setCanCreateDirectories:YES]; + + [panel beginSheetForDirectory:nil file:[[commandBundleArray objectAtIndex:[commandsTableView selectedRow]] objectForKey:@"bundleName"] modalForWindow:[self window] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"saveBundle"]; } - (IBAction)showHelp:(id)sender @@ -439,6 +463,7 @@ } [commandBundleArray addObject:bundleCommand]; + } if (cmdData) [cmdData release]; } @@ -456,9 +481,48 @@ // Commit all pending edits if([commandBundleArrayController commitEditing]) { - NSLog(@"%@", commandBundleArray); - [[self window] performClose:self]; + + // Make the bundleNames unique since they represent folder names + NSMutableDictionary *allNames = [NSMutableDictionary dictionary]; + NSInteger idx = 0; + for(id item in commandBundleArray) { + if([allNames objectForKey:[item objectForKey:@"bundleName"]]) { + NSInteger i = 0; + NSString *newName = [NSString stringWithFormat:@"%@_%ld", [item objectForKey:@"bundleName"], i++]; + while([allNames objectForKey:newName]) { + newName = [NSString stringWithFormat:@"%@_%ld", [item objectForKey:@"bundleName"], i++]; + if(i>100) { + return NO; + } + } + [[commandBundleArray objectAtIndex:idx] setObject:newName forKey:@"bundleName"]; + } else { + [allNames setObject:@"" forKey:[item objectForKey:@"bundleName"]]; + } + idx++; + } + + BOOL closeMe = YES; + for(id item in commandBundleArray) { + if(![self saveBundle:item atPath:nil]) { + closeMe = NO; + NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while saving “%@”.", @"error while saving “%@”"), [item objectForKey:@"bundleName"]] + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@""]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; + break; + } + } + if(closeMe) + [[self window] performClose:self]; } + + [[NSApp delegate] reloadBundles:self]; + } - (BOOL)saveBundle:(NSDictionary*)bundle atPath:(NSString*)aPath @@ -525,6 +589,80 @@ } +/** + * Sheet did end method + */ +- (void)sheetDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo +{ + + // Order out current sheet to suppress overlapping of sheets + if ([sheet respondsToSelector:@selector(orderOut:)]) + [sheet orderOut:nil]; + else if ([sheet respondsToSelector:@selector(window)]) + [[sheet window] orderOut:nil]; + + if([contextInfo isEqualToString:@"removeSelectedBundles"]) { + if (returnCode == NSAlertDefaultReturn) { + NSIndexSet *indexes = [commandsTableView selectedRowIndexes]; + + // get last index + NSUInteger currentIndex = [indexes lastIndex]; + + while (currentIndex != NSNotFound) { + + // Move already installed Bundles to Trash + NSString *bundleName = [[commandBundleArray objectAtIndex:currentIndex] objectForKey:@"bundleName"]; + NSString *thePath = [NSString stringWithFormat:@"%@/%@.%@", bundlePath, bundleName, SPUserBundleFileExtension]; + if([[NSFileManager defaultManager] fileExistsAtPath:thePath isDirectory:nil]) { + NSError *error = nil; + NSString *trashDir = [NSHomeDirectory() stringByAppendingPathComponent:@".Trash"]; + + // Use a AppleScript script since NSWorkspace performFileOperation or NSFileManager moveItemAtPath + // have problems probably due access rights. + NSString *moveToTrahCommand = [NSString stringWithFormat:@"osascript -e 'tell application \"Finder\" to move (POSIX file \"%@\") to the trash'", thePath]; + [moveToTrahCommand runBashCommandWithEnvironment: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"), thePath] + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:[error localizedDescription]]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; + break; + } + } + [commandBundleArray removeObjectAtIndex:currentIndex]; + // get next index (beginning from the end) + currentIndex = [indexes indexLessThanIndex:currentIndex]; + } + + [commandBundleArrayController rearrangeObjects]; + [commandsTableView reloadData]; + + // Set focus to table view to avoid an unstable state + [[self window] makeFirstResponder:commandsTableView]; + + [removeButton setEnabled:([commandsTableView numberOfSelectedRows] > 0)]; + } + } else if([contextInfo isEqualToString:@"saveBundle"]) { + if (returnCode == NSOKButton) { + if(![self saveBundle:[commandBundleArray objectAtIndex:[commandsTableView selectedRow]] atPath:[sheet filename]]) { + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while saving the Bundle.", @"error while saving a Bundle") + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@""]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; + } + } + } + +} + #pragma mark - #pragma mark NSWindow delegate @@ -561,7 +699,33 @@ } #pragma mark - -#pragma mark TableView datasource methods +#pragma mark SRRecorderControl delegate + +- (void)shortcutRecorder:(SRRecorderControl *)aRecorder keyComboDidChange:(KeyCombo)newKeyCombo +{ + + if([commandsTableView selectedRow] < 0 || [commandsTableView selectedRow] > [commandBundleArray count]) return; + + // Transform KeyCombo struct to KeyBinding.dict format for NSMenuItems + NSMutableString *keyEq = [NSMutableString string]; + [keyEq setString:@""]; + if(newKeyCombo.code > -1) { + if(newKeyCombo.flags & NSControlKeyMask) + [keyEq appendString:@"^"]; + if(newKeyCombo.flags & NSAlternateKeyMask) + [keyEq appendString:@"~"]; + if(newKeyCombo.flags & NSShiftKeyMask) + [keyEq appendString:@"$"]; + if(newKeyCombo.flags & NSCommandKeyMask) + [keyEq appendString:@"@"]; + [keyEq appendString:[aRecorder keyCharsIgnoringModifiers]]; + } + [[commandBundleArray objectAtIndex:[commandsTableView selectedRow]] setObject:keyEq forKey:SPBundleFileKeyEquivalentKey]; + +} + +#pragma mark - +#pragma mark TableView data source and delegate /** * Returns the number of query commandBundleArray. @@ -604,10 +768,13 @@ */ - (void)controlTextDidEndEditing:(NSNotification *)aNotification { + if([aNotification object] != commandsTableView) return; NSString *newBundleName = [[[aNotification userInfo] objectForKey:@"NSFieldEditor"] string]; + NSInteger selectedTableRow = [commandsTableView selectedRow]; + BOOL isValid = YES; if(newBundleName && [newBundleName length] && ![newBundleName rangeOfString:@"/"].length) { @@ -634,48 +801,17 @@ } // If not valid reset name to the old one - if(!isValid) - [[commandBundleArray objectAtIndex:[commandsTableView selectedRow]] setObject:oldBundleName forKey:@"bundleName"]; - + if(!isValid) { + if(!oldBundleName) oldBundleName = @"New Name"; + [[commandBundleArray objectAtIndex:selectedTableRow] setObject:oldBundleName forKey:@"bundleName"]; + } + [commandsTableView reloadData]; isTableCellEditing = NO; } -#pragma mark - - -/** - * Sheet did end method - */ -- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo -{ - - if([contextInfo isEqualToString:@"removeSelectedBundles"]) { - if (returnCode == NSAlertDefaultReturn) { - NSIndexSet *indexes = [commandsTableView selectedRowIndexes]; - - // get last index - NSUInteger currentIndex = [indexes lastIndex]; - - while (currentIndex != NSNotFound) { - [commandBundleArray removeObjectAtIndex:currentIndex]; - // get next index (beginning from the end) - currentIndex = [indexes indexLessThanIndex:currentIndex]; - } - - [commandBundleArrayController rearrangeObjects]; - [commandsTableView reloadData]; - - // Set focus to table view to avoid an unstable state - [[self window] makeFirstResponder:commandsTableView]; - - [removeButton setEnabled:([commandsTableView numberOfSelectedRows] > 0)]; - } - } - -} - #pragma mark - #pragma mark Menu validation @@ -685,10 +821,14 @@ - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { + // Allow to record short-cuts used by the Bundle Editor + if([[NSApp mainWindow] firstResponder] == keyEquivalentField) return NO; + SEL action = [menuItem action]; if ( (action == @selector(duplicateCommandBundle:)) || (action == @selector(revealCommandBundleInFinder:)) + || (action == @selector(saveBundle:)) ) { return ([commandsTableView numberOfSelectedRows] == 1); @@ -770,6 +910,8 @@ @end +#pragma mark - + @implementation SPBundleEditorController (PrivateAPI) - (void)_updateInputPopupButton @@ -777,6 +919,8 @@ NSInteger anIndex; + if([commandsTableView selectedRow] < 0 || [commandsTableView selectedRow] > [commandBundleArray count]) return; + NSDictionary *currentDict = [commandBundleArray objectAtIndex:[commandsTableView selectedRow]]; NSString *input = [currentDict objectForKey:SPBundleFileInputSourceKey]; diff --git a/Source/SPConstants.h b/Source/SPConstants.h index 0284cfc8..d6544549 100644 --- a/Source/SPConstants.h +++ b/Source/SPConstants.h @@ -455,6 +455,7 @@ extern NSString *SPBundleFileInputSourceKey; extern NSString *SPBundleFileInputSourceFallBackKey; extern NSString *SPBundleFileOutputActionKey; extern NSString *SPBundleFileKeyEquivalentKey; +extern NSString *SPBundleFileInternalKeyEquivalentKey; extern NSString *SPBundleFileTooltipKey; extern NSString *SPBundleFileDisabledKey; extern NSString *SPBundleInternLabelKey; diff --git a/Source/SPConstants.m b/Source/SPConstants.m index 12e46bfe..212f3add 100644 --- a/Source/SPConstants.m +++ b/Source/SPConstants.m @@ -274,6 +274,7 @@ NSString *SPBundleFileInputSourceKey = @"input"; NSString *SPBundleFileInputSourceFallBackKey = @"input_fallback"; NSString *SPBundleFileOutputActionKey = @"output"; NSString *SPBundleFileKeyEquivalentKey = @"keyEquivalent"; +NSString *SPBundleFileInternalKeyEquivalentKey = @"internalKeyEquivalent"; NSString *SPBundleFileTooltipKey = @"tooltip"; NSString *SPBundleFileDisabledKey = @"disabled"; NSString *SPBundleInternLabelKey = @"label"; diff --git a/Source/SPStringAdditions.m b/Source/SPStringAdditions.m index 3198f2ff..4e2b114b 100644 --- a/Source/SPStringAdditions.m +++ b/Source/SPStringAdditions.m @@ -469,25 +469,23 @@ // Furthermore this id is used to communicate with the called command as file name. NSString *processID = [NSString stringWithNewUUID]; [theEnv setObject:processID forKey:@"SP_PROCESS_ID"]; - id doc = [[[NSApp mainWindow] delegate] selectedTableDocument]; - if(!doc) { - NSBeep(); - NSLog(@"No active document found for bash command."); - return; + id doc = nil; + if([[[NSApp mainWindow] delegate] respondsToSelector:@selector(selectedTableDocument)]) + doc = [[[NSApp mainWindow] delegate] selectedTableDocument]; + if(doc != nil) { + [doc setProcessID:processID]; + + [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryInputPathHeader, processID] forKey:@"SP_QUERY_FILE_PATH"]; + [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultPathHeader, processID] forKey:@"SP_QUERY_RESULT_FILE_PATH"]; + [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultStatusPathHeader, processID] forKey:@"SP_QUERY_RESULT_STATUS_FILE_PATH"]; + [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultMetaPathHeader, processID] forKey:@"SP_QUERY_RESULT_META_FILE_PATH"]; + + if([doc shellVariables]) + [theEnv addEntriesFromDictionary:[doc shellVariables]]; + + if(theEnv != nil && [theEnv count]) + [bashTask setEnvironment:theEnv]; } - [doc setProcessID:processID]; - - [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryInputPathHeader, processID] forKey:@"SP_QUERY_FILE_PATH"]; - [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultPathHeader, processID] forKey:@"SP_QUERY_RESULT_FILE_PATH"]; - [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultStatusPathHeader, processID] forKey:@"SP_QUERY_RESULT_STATUS_FILE_PATH"]; - [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultMetaPathHeader, processID] forKey:@"SP_QUERY_RESULT_META_FILE_PATH"]; - - if([doc shellVariables]) - [theEnv addEntriesFromDictionary:[doc shellVariables]]; - - if(theEnv != nil && [theEnv count]) - [bashTask setEnvironment:theEnv]; - if(path != nil) [bashTask setCurrentDirectoryPath:path]; else if([shellEnvironment objectForKey:@"SP_BUNDLE_PATH"] && [[NSFileManager defaultManager] fileExistsAtPath:[shellEnvironment objectForKey:@"SP_BUNDLE_PATH"] isDirectory:&isDir] && isDir) -- cgit v1.2.3