Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2006-119
$eventId
ID of event: wwdc2006
$eventContentId
ID of session without event part: 119
$eventShortId
Shortened ID of event: wwdc06
$year
Year of session: 2006
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC06 • Session 119

Creating Great Automator Actions: The Basics

Application Technologies • 57:17

Learn the basics of developing great Automator actions. We'll provide practical guidance on how you can create Automator actions using Cocoa bindings and a variety of programming languages, including Objective-C,as well as AppleScript and other scripting languages.

Speakers: Todd Fernandez, Emilie Kim, Brooke Callahan

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Good morning and welcome to session 119, Creating Great Automator Actions: The Basics. I'm Todd Fernandez, the Automator Engineering Manager, and I'm really excited to get things kicked off this morning. I'm going to give you a brief introduction, get you excited about creating Automator actions, and then turn things over to members of my team who will teach you everything you need to know about creating great actions.

Making the right decisions about what kind of actions to create and then how to create them in the best way, following guidelines we recommend so that they behave consistently with other actions that exist on the platform, making them much easier for users to adopt them and integrate them into their workflows.

So at the outset, I want to emphasize that this session is focusing on Mac OS X 10.4 Tiger, what you can do today to create great Automator actions and ship them for your customers. At 2:00 this afternoon in this very room, we'll have another session on advanced topics that will focus more on the new features we're introducing in Leopard, some of which you may have seen me demo on Monday. So that you can begin planning ahead for adopting those features for your actions that will ship with Leopard.

So to get started, I wanted to try to review where we've been, what's happened since the last time we were here together, a little over a year ago. We had just shipped the initial version of Automator in Tiger, and we had a number of goals that we were trying to achieve by creating Automator.

First of all, we wanted to make it easier for users of all kinds, whether they're developers or just ordinary users, or maybe even your grandma, to use automation to make their lives simpler and easier. More specifically for you, we wanted to make it easier for you to create new automation tools in whichever language you prefer. So if you want to use AppleScript, use AppleScript. If you want to use Objective-C, use Objective-C.

And if you want to use Perl or Python or any other language you like, you can do that and create great new tools. And finally, we want to be able to tie all this together and make all these new tools work seamlessly and efficiently together. So again, reinforcing our first goal, making it easier for users of all kinds to use automation. So how did we do?

Well, we had one big vote of confidence from the editors of Macworld, who... awarded us an Editor's Choice Award for Best Productivity Software last year. So that was very nice of them, and I can reinforce that with some of the words from one of those editors. I think this makes it clear that they believe that we achieved our first goal. But enough tooting our own horn. What about our goal for you?

Here I really want to thank you because your response has been overwhelming and we're thrilled to have over more than 2,000 actions that have been released in the 16 months since we released Automator in Tiger. So thank you very much. We really appreciate the support. In fact, this is just a sampling of some of the many applications that now ship with built-in Automator actions, and we certainly hope to see some of your applications join this exclusive club.

In fact, Apple itself is beginning to do this with some of the applications it ships outside of Mac OS X, such as Aperture and Soundtrack Pro and Keynote, and we certainly encourage you to continue to do this. Beyond specific applications, we've also seen a great number of websites that have sprung up to create a great community and ecosystem around Automator, making it easy for users to find new actions and information about how to use them and incorporate them into their workflows.

As a great example of this, some of you may have gone to the Apple Design Awards last night where we presented the inaugural Best Mac OS X Workflow Award. And we were very pleased to see Ben Waldie, whose website was appearing there, was given the award for a great set of over 50 actions that target some of the biggest apps on the platform and work very well together.

Here's a screenshot of the winning workflow that takes photos from iPhoto and real estate listing information from a FileMaker Pro database and uses InDesign to lay that information out in a really beautiful real estate catalog that can be printed or posted on the web. So again, congratulations to Ben.

So, if I haven't convinced you already, why should you join this party and create actions for your application or technology? Well, for one thing, if you're an application developer, you can use the same tools that you're familiar with for building your application: Xcode and Interface Builder. And of course, you can reuse a lot of the same code that you use within your application.

One of the things we've seen with Automator is many of you create very powerful applications which can be intimidated for less sophisticated users. For example, like the insides of this MacBook Pro. However, what you can do by exposing that powerful technology in a well-designed, well-crafted set of simpler, easier-to-understand Automator actions is that you can make that technology more approachable for ordinary users, thereby widening your audience for your software. I'm sure none of you are interested in selling more copies of your software.

And finally, once you attract those new customers, by encouraging them to integrate your application into their automation solutions, you're helping them to make your application essential to them, because they will not want to go back to doing things by hand once they've automated a process. And finally, and of course most importantly, you'd be associating with the coolest icon.

and Otto does his pirouette there. So without any further ado, now that I hope you're really excited about creating actions and learning everything you need to know to do that, I'm going to turn things over to a great addition to the Automator team since the last time we met, who is responsible for some of the great new features that are available on Leopard, such as workflow variables. So please join me in welcoming Emilie Kim.

I'm Emilie. Let's create great Automator actions. But first, let's all make sure we're on the same page. What is Automator? Automator is an application which allows you to create automated workflows. A workflow is a process of attaining a goal. An example of such a workflow might be something like if I had my camera over here, and I wanted to take the photos from my camera and send them all the way over here to my grandma. Now, that's a workflow, and Automator allows me to automate this.

Actions make up the pieces of a workflow, and this is what you use to build it. So in our example workflow, with sending the photos from my camera to my grandmother, our actions might be something like getting the photos off of my camera and putting them onto my computer. After that, maybe I want to rename these photos, and then I'll want to scale them before I send them to my grandma, because she's still on dial-up, so she needs smaller versions of these pictures.

Automator currently ships with a very large set of actions provided for you by Apple to help you create your workflows, but if these were all the actions you ever needed, we wouldn't be here. So we've also provided you with a set of tools you can use to create your own actions. And that's what we're going to learn today.

It's extremely important we know how to create great actions because, as you can see, actions make up the pieces of a workflow. Without great actions, we can't have great workflows. So what would happen if there was no scale images action? Grandma can't receive my photos because they're too big and she becomes sad. So, as you can see, it's extremely important that we have all the actions that we can use so we can create great workflows.

So, what are we going to talk about today so we can accomplish this goal? We're going to first learn how actions work. What are the parts of an action and how do they interact with each other? We're going to learn how to create the action project in Xcode, and then we're going to learn how to implement the action, build the user interface, as well as set the action properties so the user has the best possible experience for using actions. After that, we're going to build, test, debug, install, and use the action, which is much easier done than said.

So, how about actions? There are three actions you can create. The first type of action is an AppleScript action. This is written in AppleScript. The second type of action you can create is a Cocoa action, and this is written in Objective-C. The third type of action is a shell script action, which can be done in the scripting language of your choice. For example, Bash, Python, Ruby, or even Perl, which you'll see later on in this session.

Actions can be standalone, meaning they rely on the technology of the code to perform their functionality, or they can target an application. If the action targets an application, the application must either have a scripting interface, provide APIs, or be a command line tool for the action to be able to interact with it from Automator. So, in case none of you have seen this before, this is what Automator looks like. Is there anyone, this is your first time seeing Automator?

Okay, well that's alright. To make sure we're all on the same page, let's take a closer look at Automator. So here we have the library view, which is where the user could browse by application for your action. In the middle, we have the action column, where the user can find the action they're looking for, and then they can add the action to the workflow view, and this is their workflow. So now let's take a closer look at the action.

The Action is made up of three distinct parts. The first part is the code. That's the thing we all know how to do. That's the easy part. As you saw earlier, the code can be done in three ways. It can be in AppleScript, Objective-C, or the scripting language of your choice.

On top of that, we have the user interface. This is what the user deals with when they're using your action within Automator. And then, sandwiching that, we have the action properties, which you can set to ensure the user has the best possible experience. and then when you put all that together, you have your action. But who really cares about all the other stuff? Let's get to the code. That's the exciting part. So I'm going to invite Todd back up on stage for a quick demo.

Thank you, Emilie. So the first thing I'd like to show you is just how easy it is to create a simple action using AppleScript. It's so easy even a manager can do it. Although, I guess I haven't done it yet, so that remains to be seen. So the hard part is really thinking about what you want to do with your action.

So in this particular case, I want to create a simple action that takes text as input and uses Mac OS X's text-to-speech technology to read it back to me. So within Xcode, I'm going to use the new Project Assistant to create my project. And as we can see, if I zoom in here, You can see that the action projects are right there at the top where they belong.

And they're in fact three different types, as Emilie has already explained: AppleScript, Cocoa, Definition Bundle you can hear about at 2 o'clock, and ShellScript Automator Actions. But I want to create an AppleScript action, and let's zoom back out so we don't get whiplash. So we click Next to create our project, and my lovely assistant has typed in my name already, So we're going to create an action called speak text.

The assistant creates the project from the template, and this is what I get. So let me arrange things here so we can work and give you a little tour of the project. Most importantly, again as Emilie pointed out, we're going to start off with just dealing with the code. In this case, main.AppleScript.

And before I get to the details, let me show you a few other things in the resources. One important point here to mention is that an AppleScript action is really an AppleScript Studio action. And, okay, I guess this is time for a commercial. I will be giving a hands-on session on AppleScript Studio tomorrow afternoon at 3:30, so perhaps I'll see you there as well.

The important point being here that I'm showing the AppleScript Studio dictionary, which can be very useful as you're working with your actions. And the main.nib is where your actions user interface is defined, but we're not going to add any user interface in this particular demo. So let's return to our script.

As we see, we have a single method here, a handler in AppleScript, the onRun handler. This is the code that is called by Automator when it runs your action within a workflow. And it passes you two pieces of information. It passes the input, which is the output of the previous action in the workflow, and the parameters, which are a block of information based on the user interface choices the user has made in your action's user interface, so that you can make the appropriate choices within your code. But again, we have no user interface in this first demo, so we're just going to focus on the input.

And a good habit to get into is to return the input that you're given if you're not actually changing it. And of course, since we're just reading this text back, we're not going to change it, so we're going to just return it as we got it. And it turns out, given that this is AppleScript, a very high-level, powerful scripting language that gives you all the power of the OS in a few keystrokes, all I need to do to read the text is type nine characters, say input.

That's it. Let's see how far we've gotten here. So I'm going to hit Build and Go, which compiles my action and launches Automator, passing the newly built action to it on the command line. This makes the development process very similar to building a regular application. You don't need to install the action every time you make a change.

And we see this funny-looking primary application here and speak text with the wrong icon. Hmm. Perhaps we still have some more work to do. But, well, we'll be brave. Let's pull out a pre-canned workflow that's got some text in it already and add my new action to it. And as we see, we haven't configured the UI, so let's hide that. Let's see how well this works. Automator is a fantastic boon to Mac users, not just the geeks. It's a gift to ordinary users. I never get tired of hearing that.

We'll stop tooting our own horn soon, believe me, but that's from Andy Anotko's review after he released Automator and Tiger. So that's great, we're done. Fantastic. Now I know what you're thinking to yourself. Okay Todd, well if that's how easy it is, why are we having a whole session on this? Well, let's do a little bit more testing, which I'm sure you all do with your applications. What happens if we don't give it any input?

Well, that's not so cool. We should probably just fail silently. And let's see, what happens if we pass something in that's not text, like a file name, or a file path instead? Hmm, another error. Well, you might think that's OK, because we're not passing a text. But Automator shows it as a match. Let's see. Well, we've also got the shipping speak text here. Does it work in that case?

Users S119 Documents Demo 1 Geek: Gift.Text Clipping So that works with the shipping version. How does that, why does my action not work? Well, apparently I'm not done yet. We've had at least one code problem. We're not handling null input. And this seems to be an action properties problem, because as you see the shipping action has text defined as its input, where my version of the action has anything. Hmm, I guess it's not as easy as we thought. So now that I've shown you in quite graphic detail that it's not quite that easy, let me turn it back over to Emilie to teach you everything else you need to know about creating great actions.

[Transcript missing]

So, as you can see, Todd's action has a few problems here and there, but being a manager, Todd wants us to add new features before we actually fix the bugs. So, we're going to take a look at adding a user interface to our action first, before we go and fix the problems he introduced.

So, we're going to talk about the user interface of an action, and as you saw in Todd's demo, this is also known as the main.nib file. So, we're going to open up this file in Interface Builder and add our user interface elements. So, here is what our Action View looks like in Interface Builder. We've added a text label called "voice" to label our pop-up button, which contains a list of voices that we have on the system that we can speak with.

We then go to the Bindings Inspector of Interface Builder and we have bound, in this case, the selected object for the pop-up button to the key chosen voice. This allows the pop-up button in our user interface to talk with our code. If you want a more dynamic user interface, you can use AppleScript Studio Handlers to populate your user interface and Todd will explain more about that in his next demo.

So we've added a pop-up button to this, but what else can we add? Actually, you can add any element you have in Interface Builder to your actions user interface, including the AM Path pop-up button, which is in the Automator palette, which allows the user to select a path. This is used very often in Automator actions that ship with Automator, so I would encourage you to take a look at that.

So, let's go over some guidelines when creating your user interface for your action. First and most importantly is to maintain a consistent look and feel. Many developers create actions and we want the user to have a good experience when using Automator with all of these actions. So it's essential that you maintain a consistent look and feel to encourage this.

Additionally, minimizing vertical space is extremely important because as you can see, when users add actions to a workflow, they stack on top of each other. So it's very important that the user has as much vertical space as possible. You also want to give the user feedback. For example, if your action adds text to the end of a file name, you might want to give the user an example of what their file name will look like after it goes through your action.

For examples of actions which follow these guidelines, you can look at the actions that currently ship with Automator. And if you want the complete guidelines, you can read the Automator Programming Guide. So, we've talked about how to add a user interface to our action, and we've gotten the feature Todd wants us to add. So now we can go back and fix some of the bugs that he had.

So to do this, we're going to take a look at setting the action properties of an action. There are four properties you can set for an action. You have the parameters, the input and output of an action, the required resources, and the warnings you can set for your action.

You can set all this in the target inspector in the action project. So let's first take a look at the parameters. To set the parameters, you connect basically the user interface element to your code. In this case, this is the pop-up button, and it connects to chosen voice in our code.

To set this, you would go to the target inspector and select the parameters section and you can see here we have chosen voice as type string and we have no default value since we already populated the menu. More generally though, if you have user interface elements you want to connect through parameters, if you had a text field, you would want to set its type to string, and you can also set a default value, which first shows up when the user loads your action. If you have an AMPath pop-up button, which I mentioned earlier in the Automator palette, you would also set its type to string and you could have it start out with, say, pictures.

If you had a pop-up menu index bound to your parameter, you would bind it to the integer and you could set it to 2, for example. Or if you had a checkbox, its type would be Boolean. So now that we've talked about the parameters, let's take a look at the input and output types for an action. This is especially important because as you can see, Todd's action didn't quite work with files and folders.

So let's find out why. Here you can see the input and the output for an action. But first let's focus on the input. In the target inspector, you can see that there are many options you can use when specifying the input for your action. So let's take a closer look.

First you can see acceptable input types that your action can take in. These are UTI strings and you can actually set multiple input types for your action. You can also just say whether your action requires input or whether it's optional and whether your input should be a list of items or a single item. An Automator will take care of these conversions for you.

So that wasn't a very exciting example of input, speak text, so let's take a look at a more exciting example: New Mail Message. As you can see, New Mail Message has multiple input types and it has the optional box checked. So let's take a closer look at what having multiple types entails.

New Mail Message can accept two types: alias objects and text objects. If you send in alias objects, which are essentially files and folders, into New Mail Message, you see a connection here showing files and folders connection. This tells Automator to send in files and folders to New Mail Message, and then New Mail Message says, "I'm going to set these as the attachments to my message."

New Mail Message also accepts text objects, which are text, and if you send these into New Mail Message, the connection shows up as text, and that gets set as the body for the message. So this is what having multiple input types entails. But it's extremely important to know that your actions code is what takes care of what to do with different input types. So in New Mail Message's code, it would say if the input is files and folders, set them as the attachments, and if the input is text, then set it as the body of the message.

So, now let's take a look at the optional box. But to fully understand what this box does, let's uncheck it first and see what happens. If you then add new mail message to your workflow, you see this red text at the top that says "Files and Folders". This indicates that there is a broken connection.

This is not a good experience because you should be able to create just a blank message without any input. So, if we check the optional box, we can see that now we have the option to either use the results from a previous action if there is one, or we can just ignore the results altogether and just create a blank message.

So, now that we've talked about the input, let's take a look at the output. This is very similar to the input. In the target inspector you can set its properties, and it is also done by UTI types, and you can have output as a list of items or a single item.

So, we've talked a lot about the input and output, so what are some guidelines you should follow? You should make your input and output types as specific as possible. In Todd's case, he started out with his input and output types as AppleScript objects, and if he's paying attention, he'll know that he has to change them to AppleScript text objects for his action to work correctly.

Additionally, if your action doesn't actually need input, what you should do is leave the types as general as possible and then simply return the input as the output. You can also specify multiple input types, as you saw with New Mail Message. It's important to remember that it's your code that deals with what to do with these multiple input types.

You might be asking yourself, "I'm supposed to make my input types as specific as possible, and I can specify multiple input types. Does that mean if I wanted SpeakText to accept text, files and folders, and URLs, would I have to specify both the AppleScript versions and the Cocoa versions and all of that?" The answer is no. You don't have to do this. In fact, all you have to do is set your input type to a text object. To understand why this happens, let's take a look at conversion actions.

Here we have files and folders being passed into SpeakText as text, and we see a connection here: files and folders to text. So, what's going on here? In between these two actions, there is a conversion action which converts files and folders to their textual representation, which is then what SpeakText uses to speak it.

So, this is why conversion actions allow the files and folders to be passed into an action which only accepts text, and it will still work. So, conversion actions glue actions together. They're added invisibly and automatically, so you actually don't even have to worry about it, and neither do your users.

There are many built-in conversion actions which ship with Automator, so that's why all the actions we provide work, but if you have your own custom data types that you use in your actions, you need to create your own conversion actions so your data types can play well with the other actions in Automator. And to learn more about this, I encourage you to come to the advanced session this afternoon at 2 in this room.

So we've talked a lot about the input and output. Now let's make sure the user has a good experience when, for example, if you have an application that needs to be on the system for your action, such as iPhoto. So to do this, you could set the required resources. And if the user tries to add your action and they don't have iPhoto on their system, they would be presented with a sheet such as this, telling them that the action might not work correctly.

To set the required resources, you again go into the target inspector and you can set the required resource by application or by creator code or by file. This is to make sure your user has the best possible experience in case they don't have that application on their system.

To also make sure that the user has the best possible experience in using your action, you want to set the warnings for your action. In case your action makes changes to a user's input, you'll want to let them know with a sheet such as this, saying that their images might be changed if it goes through this action.

So, again to the target inspector and let's look at these options. There are three warning levels you can set for your action. The first one is Safe. This is the default warning level and an example of this might be copy finder items. This certainly doesn't change the user's input, so this is a safe warning level.

The second type of warning level is reversible. And this basically means that the user can take back the changes that they made after sending it through your action. An example of this might be flip images. If the user passes some photos through flip images, if they don't like the results, they can just send them back through flip images and they'd be back to the way they were. When the user tries to add flip images to their workflow, they would see a warning sheet which looked like this, encouraging them to copy their files just in case before they send it through flip images.

The third warning level is Irreversible. An example of this might be crop images. If you accidentally cropped yourself out of your wedding photos, it would be extremely difficult to re-crop yourself back into them just by sending it through again. So, you want to make sure that the user is aware of this, and auto is badged with a large warning icon indicating that there are irreversible changes. You should back up your data first.

You can also set the message in the Action Property Inspector that is displayed in the sheet, and the Action Bundle ID which you would recommend the user add before they add your action. You can also set the text of the button which says, "Yes, please add copy files before this action so my data is preserved." And you can also set the text for, "No, I like to live dangerously.

Crop away." So, we've seen all these Action Properties now, and your action works great as an action. But what about within the context of Automator? So, let's take a look now at the Library view and see what we can do to make sure the user can find your action to use it.

So, you can see you can set the action name and the icon name. You can also set the application that your action lives in, so if the user is browsing for your action, they can find it. The description for your action, as well as the category and keywords for your action if the user is searching.

So, for example, keywords for a speak text action might be something like "say", "speech", "speak", and "text". So, we've seen a lot about setting the action properties, but these are extremely important because as you can see, Todd's first demo had a lot of problems. So, I'll invite Todd back up on stage and see if he's learned anything since then.

Actually, can we still have slides, please? So I guess we know who's bucking for a promotion. So as Emilie explained, I'm going to see if I can do a little bit better with configuring all my action properties now that she's taught me what I need to know to do so.

And that new feature I just had to have, I need to be able to control what voice is used to read back my text. So we're going to add a pop-up button to our user interface. And finally, we're going to use AppleScript and AppleScript Studio to implement the behavior of our user interface and the runtime behavior of the action. So, please, to the demo machine. Let's see if I can do a little bit better this time. So let's erase the evidence of my shame.

and start from this version. So let me bring up the Target Inspector. As we can see, hopefully we can see that I've already configured quite a few of these. I've got my name set properly, the application group where the action will appear, category and icon name. My input is set to text object, the way it should be apparently, as is the output.

And here are my parameters. Now, I need to add a parameter to hold the value that the user selects in the pop-up button that chooses the voice. So let's go ahead and do that. I can add a new parameter by clicking the plus button. And let's call it "Chosen Voice". And Emilie showed it with no default value, but in fact I have an overwhelmingly favorite voice, Zarvox. I'm sure you share my opinion. So I actually want everyone that uses my action to have to switch away from my favorite voice. So I'm going to add a default value.

Excellent. So we'll see when I finally build and run my action whether or not I've gotten all the action properties configured correctly, but I believe I have. So let's move on to our user interface, our main.nib. And by double-clicking on this in the project, it will open it up in Interface Builder, our other development tool that we need to use to create actions, at least actions with user interfaces. So this is what you get when you create a new project out of the template.

And I'm just going to co-opt that text to add our voice label. And let's see, what do we need? We need a pop-up button. One of the user interface guidelines is that you should use small controls in Automator actions. So let's go ahead and use the inspector over here on the right to set the size of my pop-up button to small.

and use the Aqua guidelines to line it up with my label. And finally, let's add in a progress indicator so that the user gets some visual feedback as we're populating our pop-up button. And one important thing that I occasionally forget is that I don't want my progress indicator to appear when it's not running, so I want to uncheck this display when stopped attribute in the inspector.

And let's clean up our pop-up menu. We don't need these items. And let's just have a default item of loading as we're populating our pop-up button. Let's get this lined up. Another design guideline is to have a 10 pixel border on all sides of our action controls. And I'm getting those guides by holding down the Option key with my left hand, which you cannot see, but it's really there.

All right, so now we've got our user interface laid out. Let's save our changes. But there are a few more things we need to do. We mentioned AppleScript Studio, and I actually want to use AppleScript Studio to populate our pop-up menu with all the voices available on the system.

So in order to do that, I need to attach some handlers to these items and also name them so I can refer to them in my code. So I'm going to switch in the Inspector from the Attributes pane down to the AppleScript pane, which is used for AppleScript Studio. And I want to name my pop-up button "Voice," hopefully for obvious reasons. And let's name my progress indicator "Loading."

Excellent. Now the final thing I need to do is attach a handler, an AppleScript Studio handler, which will contain the code that gets run when my action is loaded into a workflow. So I'm going to do that by attaching it to the view, which you can get by either clicking on the background in the window or down here in my main view.

One other thing that I'll point out here, this AppleScript info object was added when I started adding names to my user interface elements. So that stores all the studio connections. So the handler I want to add is AwakeFromNib. This handler is called when my action is added to the workflow and its nib is loaded from its bundle.

This is another important point. When you're adding behavior using Studio to your action, you want to add it to a secondary script, a UI script, not the main script which holds the runtime behavior of your action. You want to keep them cleanly separated. And that's what I'll show you today.

So once I've attached that handler to my view, I'm going to click the New button to create a new script to associate with it. And I'm going to create a text script called UI.AppleScript. And as we see, it appears down here in my inspector, automatically selected. So this has bound the view of my action to the Awake from Nib handler, which will be tied to UI.AppleScript. So again, let me save my Nib changes. And before I go any further, I have one more thing to do.

This will be shown again in the other demos, but we're also going to use Cocoa bindings to actually read the value that the user has selected in the pop-up button and transfer it to my script via the parameter that I added, that chosen voice parameter. So I select the pop-up button and bring up the bindings inspector.

I'm going to bind to the selected value, the actual value showing in the menu. And I want to bind that to my chosen voice parameter. and it's just that easy. So, when the user now modifies that pop-up button, it will save their choice into that parameter so that I can read it from my code. So in order to do that, let's switch back here.

And once you've associated a script with a handler, you can simply click the Edit button, which will switch me back into Xcode and insert a template for that handler into my script so that I can implement it. And this is what it looks like. So here's my UI.apple script with my Awake from Nib handler. And so you don't have to watch me type, I'm going to bring up some text clippings to build my action.

So the first thing I want to do is some housekeeping, which won't be as useful as it might be for a larger, more complex action, but I want to give you some good guidelines on how to get started. This will be increasingly useful as you add more complicated user interface elements in your action. So I'm going to set up some properties to hold references to the different elements of my user interface.

I've attached the Awake from NibHandler to the view of the action, so I know that the object that's passed into it is in fact that content view. And then I can get its super view, which is the overall action view reference, and from that get my action parameters. AppleScript Studio allows you to actually call Cocoa methods, so this is actually calling the method action on the action view to get a reference to the action, and then I can get its parameters.

Now let's get to more interesting code. What we want to do is when we load our action, we want to start the progress indicator so the user gets some visual feedback and then populate our menu with the system voices available. And of course after we do that we want to stop the progress indicator.

So that's what these three lines do. We're going to start the progress indicator, load our menu, and then stop. Now I know what you're thinking, "Oh that manager, he's forgotten he's got a handler there he hasn't implemented." Well let's put that in as well. And let me walk you quickly through this code.

This is less interesting because this is highly specific to speak text. This is where your application logic or action logic would go. But we're going to again use call method to read from the NSSpeechSynthesizer class the available voices, get their names, Clean the menu out and add a new menu item for each voice name. And finally, set the current menu item to the current choice of the user or the system default if they haven't made a choice yet.

So that's the code we need for our Actions user interface. We also, I think, need to do a little bit better with the runtime behavior so that we avoid some of those other problems that we saw in my first attempt. So again, this is what we get out of the template.

Let's try a more sophisticated version. So the first thing, this first line is of great interest. This is in fact how you read a parameter from the parameters block. Again, that's my chosen voice parameter that the user will set by interacting with the pop-up button, and the binding will write the value into the parameters block.

So I can set my AppleScript chosen_voice variable to that value and use it within my code. So I'm going to verify that the voice is installed and then iterate through a list of text that may have been passed in, speaking each one using the chosen voice. And then again, returning my input because I'm not changing it.

And again, we've got that getNames, which is just a method to get a list of the available voice names. So let's make sure we implement that. Again, using the CALL method to call the Cocoa class NSSpeechSynthesizer. So let's see, have I forgotten anything? No, I don't think so. Let's build and go and see how well I've done this time.

Hmm. I guess this is time for a joke. No. I know you would have loved it. You can imagine the funniest joke you've ever heard. So, you know what? I made you listen to that already. Let's try something a little bit more classic. So let's find my action. As we can see, it now has the right icon and its description is filled out.

And as you can see, this is my action because it's Xarvox! So, you know what, I'm not going to make you listen to the whole thing. So let's... I mean, Lincoln was a great writer, but time is limited. Four or seven years ago our fathers brought forth on this continent a new nation.

I'm feeling more patriotic already. Alright, well that's great, but my first version worked that well. Let's see how else it works. Let's try no input. Okay, well now I just fail silently. And let's try files and folders. Now that you can see that I'm specifying the input correctly.

Users s119 documents demo1git gift.txt clippe And in fact, let's verify that some more behavior that you may not have seen before. Automator allows the user to specify that they want to actually have the user interface presented to them when the workflow runs, so they can make a choice at that time.

So let's say that whenever I want some text to be read back, I want to actually pick my voice at the time. So I'm going to check show action when run. And in that case, I get The UI of the action when the workflow runs, and I can choose a different voice, though it pains me to do so. Users S119 documents demo 1 geek gift.txt clipping.

Wow, that's awesome. And as you can see, the voice has picked up the change that I made at runtime. So it looks like my action is behaving correctly. I think that I deserve a round of applause from at least Emilie for-- Back to slides, please. So just to sum up what you just learned, we learned how to set action properties and make sure that our action looks and behaves correctly as the user interacts with it within the Automator UI. We learned how to add a user interface, not a super complicated one, but it really is the same process for any other user interface element that you want to select from IB's palette and add to your actions user interface.

And then we learned how to bind the value that the user chooses in the interface to our code and make use of it within our action runtime logic. And finally, we learned a little bit about how to attach AppleScript Studio handlers to make our interface a bit more dynamic, in this particular case, to load our pop-up menu with the system voices.

And if you are interested in learning more about AppleScript Studio, again, I encourage you to attend my hands-on session tomorrow afternoon. And with that, I'm very pleased to introduce another new member of the Automator team since last we met, Brooke Callahan, again, responsible for some of the great new features in Leopard, the Watch Me Do action. So please welcome Brooke.

Thanks, Todd. So, hi everybody, I'm Brooke, and I'm going to talk to you about writing Automator actions in Cocoa. Good news is, not a whole lot different. But first we've got to talk about the Automator framework. In the Automator framework there are a few classes to represent actions. There's AM action, the abstract superclass. AM bundle action, this is what you would inherit from if you were writing an action in Cocoa. And then there's also AM AppleScript action, which you saw earlier, and AM ShellScript action, which you'll see in a little bit.

But for right now, let's take a look at BC Speak Text, which is the action that I wrote in Cocoa. So, first I'm going to show you the action properties, which there's very little difference between the different action types. And then the code itself, which you're going to notice there's a lot less of, and the user interface. So, can we switch to demo, please?

So here's my project that I created using the Cocoa Automator Action template. In the target inspector here, we see there's one change from Todd's actions, and that's that the principal class is BCSpeakText. When you're writing an Automator action using Cocoa, you'd create your own subclass of amBundleAction, and any time you change the name, you must also change the name here, or else your action just won't work. The other two changes are the input and output are now com.apple Cocoa.string. This is so that I don't have to unpack the NSApple event descriptor myself, and it'll just give me a string as input.

For the code itself, I've defined two methods, one returning an array of voices that I can bind to in my user interface. and another one, RunWithInput. This is the method that you'd-- Implement yourself to define what Automator is going to do when you run it. It's the same thing as the on-button handler that Todd implemented earlier.

Now in the main.nib, there's no AppleScript info because I'm not binding into any... AppleScript Method Handlers. Instead, I have this Voices Controller Which is bound to that voices method I showed you. And I have the pop-up button with its content array bound into the voices controller and the content values bound to the voice name of the dictionaries in that A Ray Controller.

And then also the same thing that Todd had, I had the selected value bound to the chosen voice. One small change here though is that since I have yet another feature, I have the multiple values placed, well basically I have all these fields filled out as system voice and this is basically all my error checking in case something goes wrong, someone messes with the workflow file in some way. I will have a default value show up instead of having an error. So, with that said, let's test it. Back to the getting spirit, break and dress.

And so you can see it's my action now. It has the system voice. I didn't explain to you what this was earlier, but it's essentially the voice that you set in system preferences so that any time the system needs to talk to you. It will use that voice. Four score and seven years ago our fathers brought forth on this continent a new nation. Okay. So back to slides.

We saw the differences between AppleScript and Cocoa actions that the, really the only difference between the InfoP-List, the configuration of the action is the principal class and the input and output. And the input and output you don't necessarily need to change if you like unpacking Apple and Event descriptors yourself.

The code itself, if you're implementing in Cocoa, can be much more terse. You don't have to write nearly as much and the user interface can be completely done using bindings if you'd like. So now with that, I'd like to introduce, well, I'd like Emilie to come back up and show you how to make your action complete.

So we just saw a lot of great demos. First we saw Todd fix up his action in AppleScript, and then we saw Brooke's great action in Cocoa. And you can see that setting your action properly and carefully can definitely make your action a whole lot better. So now that we've seen these two great demos, how do we make it complete?

Well, first we need to test and debug just a little bit. I know we all like to think we write perfect code, but every once in a while there's a few bugs. So in the demos that we saw, Todd and Brooke were both using build and go. But if you're having problems in your code, you can also do build and debug and use the debugger of your choice. From Xcode 2.1 and onward, in all the action templates, we have a command line tool called amlin, which is automatically run when you build your action. This is essentially a verification tool which checks for errors in both your user interface file as well as your action properties.

So now we've cleaned up our action. It runs. It builds. And we think it's fine. It's great. And we add it to the workflow, and it's not doing quite what we expected. So to debug it once it's in your workflow, you can add view results actions both before and after your action so you can see what the input is coming into your action as well as what your action is returning as its output.

And I'll take this moment to mention that in Leopard, we have a new result, which I implemented. So I encourage you to come to the session this afternoon and take a look at it. Additionally, you can also add an Ask for Confirmation action to your workflow so you can pause or cancel the execution of the workflow if you see that something isn't going correctly.

So, we've tested our action, we've debugged it, everything's great. So now let's install the action. Actions that ship with the OS live in System Library Automator, but your actions should live in the appropriate Library/Automator folder. Additionally, if your action is part of an application, it should live in your Applications Bundle.

So if you've been paying attention, you'll remember that there are three types of Automator actions, and we took a look at AppleScript and we took a look at Objective-C, but what about the last one, ShellScript? And that's because I've saved the best for last, and so we're going to take a look at ShellScript actions now.

So we're going to see a Perl action that I've written called GeekText, and you might be able to guess what this will do. So we're going to learn how the user interface doesn't vary, essentially, from both AppleScript actions and Cocoa actions, and then we're going to take a quick look at the code. So switch to demo, please.

So here's the GeekText project that I've created. And I did this by, again, going to the Assistant and creating a shell script action. And when you do so, type in Dvorak, so Cordy is very slow for me. So when you first create your shell script action, you'll see that here you have to set what you're going to write your action in. So in my case, I had said it's a Perl. But we don't really care about this project. Let's take a look at the Geek Text project. So the user interface, we see that here I have my pop-up.

Found its selected tag to the key level. And so that isn't any different from the other actions that you already saw. And then in my script file, I have this set to Perl, and here is where I grab the value of the binding that I had set. And the bindings are passed in as environment variables, so you just get your environment variables as you would with the scripting language of your choice, and you have your bindings. So let's take a look and see what this action will do, in case you haven't figured it out already.

Keep remembering that favorite joke of yours. All right. So. Here, my action is living in Terminal because it was a shell script action, but of course you can change that in the action properties. So, here's my action. My lead level is Noob, and you can see I have example text that I implemented with Studio Handlers. And let's see what happens when I run this.

Great. Looks awesome. Totally legible. Let's change it to Leet. Okay, but I think I'm an uber-leet hacksaw, so let's see it again. Wow. Well, but, you know, that wasn't enough, so let's see what happens if we speak this. We'll use our Vox. F0, 2, 5, 0, 23, 4, 53, 33, 34, 25, 490 Tifferifferiffer 490. That's great. Alright, back to slides please.

So, what did you learn? Well, first you learned that when you translate the Gettysburg Address to Geek Text, it sounds like "tifferifferiffer." You also learned how to set the shebang, which was setting sh to Perl, and you learned how to implement the action in Perl. You also learned how to extract the bindings, but not only that, you learned how to extract the bindings with any shell scripting language, not just Perl, because they're just passed in as environment variables.

So, now that we've covered AppleScript actions, Cocoa actions, and Shell script actions, let's step back and take a look at what we've learned in this session. Well, we started out with what Automator actions are. We learned about the types of actions and the parts of the actions and how they interact with each other.

After that, we learned why actions are extremely important. We learned that if we want great workflows, we first need great actions, and if you want to put a new face on your application's technology, then creating great Automator actions is very important. We then learned how to create the action projects and how to implement an AppleScript action.

After that, we designed a little bit of the user interface for an action, and then we set the action properties. We then saw how to implement a Cocoa action and build, test, run, and install an action, which, as you saw, was easier done than said, and how to implement a Perl action, and now we know how to create great Automator actions. Well, to me, that looks an awful lot like we just did a workflow.

We started out with what Automator actions are, and then we went all the way through these steps, and we ended up, we now know how to create great Automator actions. So you can see how having the right steps in your workflow is extremely essential to creating a great workflow. So that's why we need you to go out and create great Automator actions.

So, for next steps, you can of course read the documentation, but who wants to do that? So take a look at the example projects also in Developer Examples Automator. There is the advanced topics session this afternoon at 2 in this room, and you can also come to the lab after that at 3:30 where the Automator team will be more than happy to answer all of your questions. And after that, just write and ship great actions for people to use.

So for related sessions, you can attend any of these great sessions. And for more information, you can contact Sal Segoian, our Automator Product Manager. Or if you want to learn how to write bad actions, you can contact Todd Fernandez, the Automator Engineering Manager. You can also email the Automator Developers mailing list or go to the developer website for more resources.