macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Controlling Your Mac with AppleScript and Java
Pages: 1, 2

NSAppleEventDescriptor: Listening to Replies

In the code that we just wrote, we executed a script that performed an action. The call to execute() actually did return a reply, but we ignored it, because it was not important to our script.



Now we want to be able to execute scripts and do things with the output. The easiest replies to deal with are the ones that are just one single string. For example, if you type this script into ScriptEditor, and run it, you will get the name of the first disk on your desktop:

tell application "Finder"
    get the name of the first item in the desktop
end tell

Mine returns "Greater Scott".

Screen shot.
The script reads the name of the first item on your desktop with a reply.

Now, let's do this in Java. We can use the same file, with a few tweaks. Change the script string to be

String script = "tell application \"Finder\" \n"
    + " get the name of the first item "
    + " in the desktop \n" + "end tell";

In order to get the reply back, we need to assign a variable to the value that execute() returns. Make the line with execute() read as follows:

NSAppleEventDescriptor results = myScript.execute(errors);

This will capture the AppleScript result, and allow us to access it via Java. Add these lines after the call to execute():

String resultString = results.stringValue();
System.out.println("The first item is:"
                   + resultString);

Compile and run your application, and you should see it tell you the name of the first item on your desktop. Congratulations! Your Mac is talking, and you are listening!

Multiple Replies

Right now we can ask AppleScript to return one value, and we can read that value. But that's pretty limiting. AppleScript has the concept of lists, so it stands to reason that we would want to be able to get back a list of things from AppleScript. Continuing on with the Finder interaction, we will now get a list of every file that sits on your desktop.

In ScriptEditor, write the following script:

tell application "Finder"
    get the name of every item in the desktop
end tell

This should return you a list of everything (disks, files, folders, etc.) on your desktop. Now let's see how to parse this reply using Java.

The NSAppleEventDescriptor is a catch-all class that represents how AppleEvents are represented internally. They can contain a multitude of different types: enumerations, lists, strings, numbers, you name it. There are several methods in the NSAppleEventDescriptor class that allow you to determine the type of descriptor; for now, we're going to just assume that it's either a list or a string.

Edit your AppleScriptTest.java file, and change the script variable to be the script from above:

String script = "tell application \"Finder\" \n"
    + " get the name of every item "
    + " in the desktop \n" + "end tell";

Edit the lines after the execute() method. We are no longer interested in the string value of the descriptor. Instead we want to get the sub-descriptors. These are accessible using the method descriptorAtIndex(). You can tell the number of sub-descriptors using the numberOfItems() method. Note that descriptors are indexed starting at index 1, not at 0 as Java programmers are used to. Using these two methods, we can iterate over the subdescriptors and print out the list of everything on the desktop. Your entire main method should now look like this:

S// This line of code is necessary because
// of a change introduced with QuickTime 6.3
// This line loads the Cocoa libraries.
NSApplication.sharedApplication();

String script = "tell application \"Finder\" \n"
     + " get the name of every item "
     + " in the desktop \n" + "end tell";

// This creates a new NSAppleScript object
// to execute the script
NSAppleScript myScript =
     new NSAppleScript(script);

// This dictionary holds any errors
// that are encountered during script execution
NSMutableDictionary errors =
     new NSMutableDictionary();

// Execute the script!
NSAppleEventDescriptor results =
     myScript.execute(errors);

// Print out everything on your desktop
System.out.println("Starting list of items "
                    + "on the desktop: ");

int numberOfDesktopItems = results.numberOfItems();
for(int i = 1; i <= numberOfDesktopItems; i++)
{
     NSAppleEventDescriptor subDescriptor =
         results.descriptorAtIndex(i);
     System.out.println("    " +
                       subDescriptor.stringValue());
}

System.out.println("Yay AppleScript!");

On my desktop, here are the results:

Screen shot.
The program lists all the items on my desktop.

As you can see, for scripts that return a list of items, those items are contained as subdescriptors underneath the result descriptor. Depending on the complexity of the script, descriptors could be nested many levels deep.

Now you should be able to see some of the potential of combining AppleScript and Java. AppleScript gives you the fantastic power to interact with your applications in a way that is unmaginable when using plain Java, and Java gives you all the power of an enterprise-quality, full-fledged programming language.

Used together, you can set up your Mac as a sort of command center, and use Java to access it from anywhere. Think about editing your iCal calendars from your office, or controlling iTunes from another room in your house. Almost anything that you can do on your Mac, now you can do from somewhere else.

Scott D.W. Rankin is a Senior Software Engineer with Back Bay Technologies and a die-hard Mac fan(atic).


Read more AppleScripting Mac OS X columns.

Return to the Mac DevCenter.