views:

211

answers:

2

I'm tearing my hair out trying to create a new album from a Cocoa Application. In applescript it's a nice simple procedure:

tell application "iPhoto"
    new album name "Album"
end tell

But I can't work out how this is done in Cocoa via the Scripting Bridge. I've tried this:

iPhotoApplication *iPhoto = [SBApplication applicationWithBundleIdentifier:@"com.apple.iPhoto"];
iPhotoAlbum *newAlbum = [[[[iPhoto classForScriptingClass:@"album"] alloc] initWithProperties:[NSDictionary dictionaryWithObject:@"Album" forKey:@"name"]] autorelease];
[[iPhoto albums] addObject:newAlbum];

But that had no effect.

Please help!

+1  A: 

I tried once to use Cocoa Scripting bridge, with no success. My workaround was to use NSAppleScript class:

NSString * scriptSource = [NSString stringWithFormat:
    @"tell application \"iPhoto\" to import from \"%@\"", path];

NSAppleScript * exportScript =
    [[NSAppleScript alloc] initWithSource:scriptSource];    

[exportScript compileAndReturnError:NULL];
[exportScript executeAndReturnError:NULL];
mouviciel
Thanks; that works nicely. Is there any way to obtain the value returned by the script?
robinjam
+2  A: 

I haven't bothered to check, but I suspect there is a bug in either sdp or Scripting Bridge where commands that have keyword parameters are targeted at the main application object are given one method name by sdp (e.g. -newAlbumName:) and a different method name by SB (-newAlbum:name:). Since you can't hack SB, you'd need to patch the sdp-generated header to use the latter method and pass nil as the first argument.

Alternatively, you could use appscript, which is more capable and less prone to application compatibility problems than SB. It also provides better development tools and support. e.g. Running your AppleScript through the accompanying ASTranslate tool produces the following objc-appscript code:

#import "IPGlue/IPGlue.h"
IPApplication *iphoto = [IPApplication applicationWithName: @"iPhoto"];
IPNewAlbumCommand *cmd = [[iphoto newAlbum] name: @"Test"];
id result = [cmd send];
has
Thank you for your response. It seems that sdp has in fact generated the header files wrong - probably because "new album" isn't in a class. I'll take a look at how appscript does it behind the scenes :D
robinjam
iPhoto's dictionary is poorly designed, but the structure and usage of the `new album` command is perfectly valid; ditto iTune's `play` command, which is another legitimate example. sdp and SB simply aren't translating application dictionary-defined commands into ObjC methods in the same way. It's a really elementary bug.
has
Appscript pretty much mimics the way AppleScript works, adjusted to suit the capabilities of the host language. Since ObjC methods don't do optional args, it uses a series of chained method calls to create the command (`-newAlbum`), pack each parameter (`-name:`), and finally send it (`-send`). It's very similar to the way that you build and send Apple events using the original Carbon C APIs (`AECreateAppleEvent`, `AEPutParamDesc`, `AESendMessage`) and maps more or less directly onto those calls.
has
Thanks for all your help - I think I'll use AppScript for stuff like this in the future. It beats Scripting Bridge any day.
robinjam