Development Tools • 1:15:13
AppleScript Studio is a set of professional application development tools that enable you to create full-featured Mac OS X applications using AppleScript. In this session, we will walk you through AppleScript Studio's most interesting features, such as toolbar support and easier-to-use data views, and teach you how to use these features to add exciting functionality to your AppleScript Studio applications.
Speaker: Tim Bumgarner
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
All right, good morning. It's great to be here. This is AppleScript Studio in Depth, session 406. It's terrific to see so many people here on a Friday morning at 9:00 in the morning, particularly since the Apple campus bash was last night. So thank you for being here and so bright and early this morning.
And my name, of course, is Tim Bumgarner. I'm a senior software engineer at Apple. Thank you. This is actually our fifth year at presenting at at Developer Conference for AppleScript Studio, so it's been five years old. That's how long I've been at Apple, actually, so it's sort of a little milestone there.
And let's take a look at our agenda. So we're going to just go through a brief introduction. Then we're going to have a hands-on project that we're going to work through, and then a little bit of information about where you can find out better documentation or improved documentation for Studio.
And hopefully, we'll have some time left so that we can do a question and answer at the end. All right. So in order to do the introduction, I need to do one of those little surveys to sort of gauge where we're at as far as experience. So how many people are new to AppleScript Studio? Wow.
That's awesome. Cool. Glad to have you here. So that makes my job a little harder. We get to go a little slower. That's great, though. It's good to know that. How many people have actually built a Studio application? Okay, good. And how many have actually shipped a Studio application? Okay, those of you that have your hands up, do you realize that it is simply a matter of checking a box, turning on Intel, recompile, and ship your application and you're on Intel.
There won't be any other work to do. I've actually went into the labs and tested all the Studio examples. They all work perfectly. So it's very simple for you to develop a universal application. So we actually get to take advantage of the fact that we're scripting using AppleScript on top of Cocoa.
So why would you want to use AppleScript Studio? Well, it's an easier approach to creating Macintosh applications. If you're not comfortable with the regular programming languages like Objective-C or C++, AppleScript is a very approachable language, and so it's a very easy way to put together real native Macintosh applications. And it's also excellent at doing rapid prototyping.
You might want to put together an example of what your application should do, and it's very quick to wire together the things using AppleScript Studio. And it also works very well and mixes in with other development languages. So inside of Xcode, as you're using AppleScript, you can pull in a little bit of Objective-C or C++ or Java code.
Some of the common uses that we find people using Studio for is to put a friend front end on Unix tools. So they have some tool that they want to expose. And it's very simple to put a UI in front of that. And using the do Shell script command in Apple Script, they can take advantage of the Unix tools.
We also find that it's a great application for working inside of a workflow. Apple Script Studio, of course, is built on Apple Script. It is excellent at talking to other scriptable applications. And so it makes a very good center for talking to the various applications to provide a workflow in your environment. Another thing that we found is people have spent a lot of time writing Apple Scripts.
And in order to provide any sort of UI, they end up doing display dialog. So I'm sure you may have seen some scripts that just kept asking me with a dialog, answer one question, answer another question, and find that it goes off and does its thing. So what they do is they can take Studio, take their existing script, and put a nice UI in front of that. And then go ahead and let it run.
And of course, the most exciting thing, which we saw in Todd's demo yesterday, is that you can use Apple Script Studio to create Automator actions. As a matter of fact, a good many of the actions that we ship in Automator use Apple Script Studio to talk to various UI elements in the action.
So this is a hands-on format. Unfortunately, there's a technical difficulty, so the code that I have is just a little newer. And that's-- what we're going to do is we're going to take this lemon, and we're going to make a little lemonade out of it. So I'm going to show you the old code and compare it to the new code, and the differences. You'll still be able to follow along.
And this is where I'm going to do another survey. So how many people would like to actually walk through and build the app with me? Okay, great. So, there's quite a few hands. So, that's what we're going to attempt to do. I'll try to go slow enough. If I go too fast, I never do that.
Ever. Let me know. So, raise your hand, holler out. Well, I won't see your hand, but go ahead and holler out. Tell me I'm going too fast. It's a little tough to see the screen. I'll try to zoom in as best as I can. But if I get too far ahead, just let me know. So, it's a very interactive thing. We'll go ahead and do it that way.
So, you should have the session material. If you don't have that, there's no way you'll be able to keep up because I won't be typing anything. I'll use demo assistant. But in your session material, there's an outline, an OmniOutliner outline or a PDF, or RTF, I'm sorry. And you can copy out the bits of code that you need. It's very clear where to do that. But if you don't have that, you won't be able to follow along.
If you don't, just go ahead and watch me, and you'll be able to pick these up later. Now, we will make the newer version that I'm going to show that we're going to build will be available after the conference, hopefully fairly soon after. So the hands-on project. So what we're going to do is we're going to build this application called ScriptView.
ScriptView is a script editor with a database built into it. What we're going to do is demonstrate new and improved features for Tiger. And so some of the improved features that we have are the data sources that we have that back up outlines and table views. They've been greatly improved, much easier to use. We have also new, we've added toolbar support. So it's very simple to create toolbars in your studio application, so it's more of a part of the regular Cocoa application.
We've also added target action support. So anywhere, particularly from Cocoa in Objective-C, where you see that there is a connection from a target to the action of a method that needs to execute, you can now set that up in script. Typically, you do this in Interface Builder. You drag a connection from one thing to the next and specify it. Now you can do that in script as well.
And that's important for toolbar support. We're also going to show you OSA Kit. This is a new framework. It's a public framework, Louis Shipp, that provides the script editor view and the dictionary view. And actually, it's the technology that all of the studio script editor and automator are all built on.
So it's actually the same code that we use is now available for you to use. And then we're going to look at some Xcode features for 2.1. If you have 2.0, you'll be able to follow along, but you won't be able to execute these breakpoint actions that we have now, which are new in 2.1.
So let's go ahead and take a look at the application in its final state so we can see what it's going to look like when we're finished. And I'm going to go ahead and just launch the built product at the end. Now, it's probably, can you see it? All right.
All right, excellent. So let's go ahead and I'm just going to, it's a script editor that has a script view here. The results are going to get put out here. And I can add records down into this table view and we'll see what that does. So I'm going to type in the wrong place. We'll go up here, do a current date. And you can see that it's actually using the same features that are in the script editor.
I can hit, bring up the code completion and choose current date and hit enter. And I can compile it, run it. And you see the results automatically get put down here. And I'm going to add that as a record down here below. Let's do front window and simply run that, add the record. And you can see that I have two different records down here. I can click on that.
And when I do, it puts the script back into the script view. So it's a way for me to capture a bunch of scripts that I have and save them. And I can save that with the document. There's also sorting is fully supported in the table view. Sort it by date here or if I want to sort by the source or the result. And you can see that the toolbar itself is fully customizable. I can drag and add things around as I like.
And I can collapse that if I like. And it's also a document-based application, so again, I can create as many documents as I'd like. I can save the document, and it works just like you would expect it to do. So that's the application that we're going to build as our hands-on project.
[Transcript missing]
So what I have-- let's zoom out of this for a moment. I am going to go into Xcode and minimize that. And I'm going to choose from the File menu New Project. This is whenever I want to begin a new Xcode project. I will select that. And you can see that there are several different categories of a lot of different types of things that I can produce out of Xcode. The one that we're looking for is in the Application group.
And there's AppleScript application. And then there's the AppleScript document-based application. So let's choose that one. Click the Next button. And then we're going to call our project Script View. So it's a capital S, capital V, Script View. All right. And when I'm finished, I'll go ahead and click on the Finish button.
And it will open up with a project. And it will be set up for us. So there's many things wired together at the beginning. One would hope. Wake up, computer. Living on a firewire drive. So here we go. This is our Xcode project. And it comes already with a couple of different scripts set up for us. This is the document script. It's the script that's executed whenever we create a new document.
And right now, it comes with a couple of handlers that we'll discuss later. The script view is the one that's attached to the application itself. So it's sort of the main script. We have our resources. We have here our document nib and our main menu nib. The main menu nib is the nib that contains our menu as the main application nib. And the document nib is the thing that gets created every time we create a document. So let's go ahead. And we're going to go into Interface Builder. And the simplest thing to do is to double click on our document nib.
All right? So everybody should be an interface builder. And we have a window here by default. It's probably not quite big enough, so we need to make it just a little bit bigger here to fit all of our views into. Now, the first thing we need to do is put in our script editor view. Now, OSAKit provides a palette for us.
And unfortunately, it is not installed by default. You actually have to go add that the first time that you want to use that. But it's very simple to do. You go to the Tools menu, go to the Palette submenu, and pick Palette Preferences. And when we bring that open, it takes us to the palettes panel. And we click the Add button.
And what it does is it takes us to the default location. This default location is generally in your developer-- your system developer palettes folder. So anything that's in that folder will automatically be loaded by IB. And you can see that that includes, like, the Studio palette, Sherlock, and others. But we're going to go back one level up to developer, select the extras group.
And inside of the extras folder-- inside of the extras folder is the palettes. And you can see there's actually quite a few extra palettes here that you can add. The AB palette is for the address book if you want to actually drag in a people chooser. The automator palette is right here. But the one we're looking for is the OSA palette. So I'm going to go ahead and select that and choose open.
And you can see what it did is over here-- is an expert in the field of web analytics and web analytics. He's been working on a number of projects that work with each of these views, and he's been working on a number of projects that work with each of these views.
And I'm not going to reposition it yet. I'm just going to go ahead and drag that in. What's going to be a little more difficult is I'll have to zoom out and bring this window over here. So we can follow along closer in the Zoom mode. And I'm going to take a script controller and drag that into our project.
The script controller is what interacts with the script view. Now that takes care of that part of it. Now what we need is we need a results view. And that simply can be just a text view. So I switch to the text palette, drag out a text view, All right. We'll set that down about here for the moment. Now, the next thing we needed at the bottom of our application in the window, in the document window, was a table view. So we'll switch over to the table palette, and we'll drag that out.
Right pace? Are we doing all right? All right, cool. If I don't hear you screaming, I'm just going to assume all is well. So we're going to drag this out, put it down here towards about the last third.
[Transcript missing]
And finally, we'll grab our script view here at the top and fill that out. So that sort of gives us our spacing that we had in the finished product. Now, what we need to do is we need to put all of these views inside of a split view. And the simplest thing to do is to go to the Edit menu.
[Transcript missing]
And you can see that now I do have a split view here. It's put all three of those views into a split view. Now, the last thing we need to do as far as the split view is concerned is we need to position it correctly.
Many times I see a lot of applications, they don't line up the edges of their views exactly right, so you get a double border at the bottom of a toolbar, sometimes in the corner they don't match correctly. So I have a little trick that I use quite a bit. And when I created the split view, it's right in the top left corner. I move using the arrow keys, I move it up two pixels by hitting the up arrow key twice, and I move it left two pixels. And then I take the window and resize it.
until it snaps to where the Aqua guideline says that it should be, and then I move it back down one pixel and to the right one pixel. And that puts the border exactly right. It'll look very polished, and look much more professional. So that takes care of the first part of setting up our view.
Now we actually need to wire together our script view and the result view. And the way that you do that in interface builder is you hold down the control key, and you click on the script controller object down here in our objects view. And I'm going to drag a connection up to the script view. And you see that it gives me some feedback that I've dragged it to the right thing. And when I let go of it, it's actually going to open up the inspector for us.
See if I can't reposition all this. Working in zoom view is so much fun. All right. So, and let's say I actually lost my connection when I did that, so I'll have to hook it up again. And you can see there it gives me two outlets. One is the result view, and one is the script view. So I select the script view and click the connect button. So that's made that connection, and I need to make one more. That's the script view. Again, holding the control key, dragging to the text view.
And this time it automatically selects the result view for me and click connect. So that takes care of the connections that we need between the script view and the result view. What the script controller does is as I compile or run, it will talk to the script controller, and the script controller will take the result and put it into the result view for us. Now we need to work on our table view. By default it comes with two columns. So what I'm going to do is sort of drill down into this by selecting it, and see if I can get my resizer here. It's always fun.
[Transcript missing]
And we make sure we don't have the table-- columns selected. We actually want the table view, and so it's always very important to look at the inspector and look at the title, and it tells us what kind of thing we have selected, so I have the table view selected. And I'm going to go ahead and change the number of columns here in this cell to 5.
And when I do that, you see that I now have five columns. We're going to do a couple other things. We're going to turn on alternating background for each row, and we're going to automatically hide the scrollers as necessary. So as we add more data, the scroll bars will appear. And then we're going to go in here and just sort of reposition some of these. Sort of fill up the space appropriately. Oop, don't drag it.
Okay. And there we go. A little wider here, a little wider there. Just kind of spread them out nice and even.
[Transcript missing]
The fourth is result. And the last one is for our comments. So we've got that looking pretty well. That takes care of most of the UI.
The one last thing we need to do is to select our split view, because what we need to do is make sure that it stretches to fit the window. So for instance, if I go ahead and test this interface under the File menu, Command-R is a shortcut, you can see it will actually an interface builder. I have my split views. I actually have the script view is already working. I didn't have to write any code, and it just will work for me. I can do the code completion here as well.
I can compile as needed. Splits look good, but what you'll notice is that when I resize the window, the content view of the split view isn't resizing to fit. So let's go ahead and quit the test mode, and by clicking on the little icon or Command-Q, we'll do that. And I'm going to get to my split view, and again, I check here in my inspector that I have it selected, and go to the size.
And what we have is the auto-sizing mechanism here. It allows us to tell Cocoa how it should stretch our views. And what we want it to do is we want it to fill up the entire space inside of the window. So we turn on both sets of those. And again, we can test that very quickly in interface builder so that you can see that, as I resize, now everything stretches and looks great.
So that takes care of the user interface. We won't have to do much more with that. And from this point on, it'll be mostly studio related. So this is typical interface builder. So this would be the same if I were doing Cocoa or if I were doing studio.
So these parts are all the same things that you work with. So let's go ahead and save the document under the File menu. I'll choose Save. Now you'll notice that there's actually an alert that comes up. And what it says is that if I save it in this format, which it's saying is currently set to be pre-10.2, then I'll actually lose some data. And whenever you're going to be using new features in the OS or in an interface builder in your Cocoa project, you have to make sure you have the right version set. So I'm going to click Cancel and go to the project window here.
And there's a nib palette in Tiger on the far right. And you'll see that there's a couple different settings we need to look at. One is the nib file format. We need to change that to 10.2 and later format. We optionally could use a text archive if we like, but we'll just leave that off.
And you'll notice here in the bottom of the window is it says incompatibilities. There's seven incompatibilities if we are setting our earliest target to be 10.2. What we need to do is change that to 10.2. And when we do that, you'll notice that all the incompatibilities go away. It's a good thing that if you don't do that, most of what we're going to use today just flat out doesn't work. So you need to make sure that that's set appropriately. So now I can go ahead and choose Save. And it will save the document for us.
[Transcript missing]
And when it's finished, we can go back over to Xcode. And we're going to build and go. And I'll just click on the toolbar item here, or I can choose it from the build menu. Build and run, I guess we call it now. And it's going to build the application and run it for us.
Now I'll sort of have to zoom out so we see the whole thing. And hide it. So you've noticed, of course, that we don't have a toolbar yet, because we haven't got around to creating that. But I still, again, have my editor here. And I can compile that. I can't run it without a toolbar yet. We have our results view. We can see that everything resizes, so it looks pretty good. So that takes care of our first steps. So we're going to stop right there and continue here.
So, what we did is we went to Xcode, we created a new project by choosing the appropriate template for our product. Then we went into Interface Builder and built its interface. And then we wired together the controller objects as needed, and then we built and tested our application.
And this is a typical process. You go into Interface Builder, build your interface, go to Xcode, build and run, and see how you did. Tim Bumgarner Okay, so the next step is to go ahead and add a toolbar to our application. And this is what we're going to do in this step.
We're going to add some icon resources. So we saw the toolbar in the finished product had a bunch of different icons. So we're going to add that to the project. We're going to add an AwakeFromNib handler. And this is, for those of you that are Cocoa programmers, will recognize the name, AwakeFromNib. Anytime something gets loaded from a nib, a method gets called in Cocoa.
It's the same thing for Studio. If you want that object to have a handler called for it, you just simply turn on AwakeFromNib. Tim Bumgarner Then we're going to go in and we're going to add the code. Tim Bumgarner And we're going to add the code to create a toolbar and its items. And then we're going to talk about and use something, a new feature in Tiger. It's really an important concept to understand. So we're going to talk about that for just a minute.
Tim Bumgarner This is the idea of a script scope. So what is a nib script scope? Up till Tiger, every instance of your scripts, there would only ever be one instance of it. So for instance, in a document-based application, I would create the first document, and I had document.AppleScript. When it's built, it actually ends up as document.SCPT.
is only one instance loaded, so that when I create another document-- it would actually reference the same script. I would only ever have one document.svpt. And actually that's not a good thing, because it makes it much harder to write your code. So if we switch to a nib script scope, and we have our first document, we get one instance.
And the next time we create the second document, or load the nib again, we get a new instance of that. So you can actually use properties inside of your script that reference things in your document. And it's unique to that individual document. It's very powerful. It's going to be a much easier way to write your code.
And you'll see that as we go. And then the last one is there's actually another scope called Object. And so you could actually have a new instance for every element, or whatever you decide to attach it to, there's a new instance of that script. So your code could be much more modular and take a more natural use of scripts inside of Studio. So let's see what it takes to build that script view. Or add the toolbar, I'm sorry.
Now, this is where it gets interesting, because my code is going to look a little differently. And hopefully, I can point out all the differences. You'll still be able to build what you have. And it's going to work just the same, except I'm going to contrast the differences and the improvements between sort of the pre-TigerWay versus the TigerWay. So let's go ahead and go back into Interface Builder. Double-click on our document nib here. And what we need to do is to select our window object. And that's easy enough to do by clicking it on the Inspector palette.
And we're actually going to go through now and name a lot of the elements inside of our document nib. And to do that, for AppleScript, you go to the Inspector and choose the AppleScript Inspector panel. And from this point, we're going to work in this inspector quite a lot. We're able to name our objects. AppleScript loves to be able to talk to objects inside of the environment, but it has to do that by a couple different ways. It can do it by index, so I can say document one.
It can do it by name, or I can say document foo, or I can do it by ID, which is another unique identifier that you can give. We're going to be using the name access to our objects. So for our window, we don't need to actually name it in this particular case, but we do need to turn on our nib handler, our AwakeFromNib. So you see that there's a nib group, and I simply click on AwakeFromNib.
[Transcript missing]
So by default, it's always set to global for backwards compatibility. So you'll have to remember to set it to nib. But this, what will happen is that now when this window is opened, I get a unique instance of the document script. It's not going to just reuse one instance of that. It's very important. So let's do that.
Now we need to kind of go back and name all of our objects. What I find is that you can sort of drill in here, click on the various different views. I find it much easier to go to our document window. And there's two little controls here. One is for an icon view. And one is an outline view.
So I actually switch it to the outline view. And if you hold the Option key down and click on the disclosure triangle for NSWindow, it'll automatically expand all the children. So now it's very easy for me to see the structure of my nib and go name things appropriately.
And so what we need to do is name our split view. And so if I go too fast, let me know. We're going to select the split view here. I verify that I've got the split view selected. And we're going to name this main. It's all lowercase, M-A-I-N.
All right? Now, you'll see that here's our script view, our result view as a text view, and they're inside of scroll views, and in order to access them, we need to name all of them. And the technique that I use is I named the script view-- we're going to use a lowercase script, capital V for view.
So I'm going to name that script view simply "script view." And I always name the scroll view that it contains the same thing, so I don't have to think about what it's actually named. And so I'm just going to copy and paste that for that scroll view. Let's go down to the text view.
And we're going to name this one result view-- again, lowercase result, uppercase V for view-- and copy that. And select the scroll view for the result view, and name it result view. All right, the last piece down here is the table view. And we're going to call this one script table. Again, lowercase script, uppercase T for table. And we copy that, name the outline of the view that it's-- or the school view that it's in to script table.
All right. Everybody keeping up? We awake? Okay, great. So we have our table columns. We need to name these table columns as well so that our data source will be able to find the appropriate column when we get to that point. So I select the first one, and that's date. And we're going to prepend all of these with a lowercase script.
So it's just script and then date. So I'm going to copy, actually, the script so I don't have to retype it every time. We're going to select the name column, script, paste that in, uppercase N for name. Do the same for source. I typed it. I forgot I can paste. All right, the result.
And the last one is the comments. Did I make any mistakes, Sal? Am I all right? Okay. Everybody there? Because if you don't have these right, your script's not going to work. And unfortunately, we won't be able to come around and get your code working like we do in our normal early bird sessions. So hopefully you've got all that.
Tim Bumgarner And also remember, in the session material, we have all of the steps. And each step is the end of that step. So if you get lost, you can always, when we finish up at step one or step two, you can grab the last one prior to that. That puts you at the beginning point or at the end point. So if you have a problem, just go up to the next step and start from there.
Tim Bumgarner So let's go ahead and save that. And what we need to do is to go ahead and implement our Awake from Nib handler that we created. So I'm going to go ahead and just make sure that we've got that on our window object. Tim Bumgarner And here it's -- go ahead. We've got our Nib and we've got our document. And it's set to the script -- scope of Nib. And so I'm going to go ahead and click on the edit button. And this will take me back.
[Transcript missing]
Okay. And you can see that I have my Awake from Nib handler. It was automatically inserted to the script for me. I didn't have to remember what its name was or what the actual parameters to it. It just inserts it for me. And I am going to use my fancy-dancy demo monkey here. And I'm going to actually add a piece of code that you don't have, and we're going to talk about that here in just a second. So I'm going to paste that in.
What I've done in this is taking advantage of that nib scope, and I've set up some properties, because these are the objects that I'm going to communicate with regularly in my script. I'm going to be working with the data source that's behind the table view. I'm going to be working with the script view, the result view, and the table view. And so by doing this, I can have these references. And in the AwakeFromNib, we assign those references, and we only need to do it once.
And then whenever I need to talk to one of those objects throughout the rest of the script, it's just a matter of using this property. Now, that's compared to the code that you actually will have on your sample, where it will have, like, script view foo of scroll view bar of window main, and after a while, it just becomes a foobar mess.
So it's -- and you have to keep those updated after a while. Every time you change the hierarchy, you would have to go through every instance that you use that and fix it. So this is a much better technique. And remember that you get -- this is a unique instance of this for every document that's created because we use that nib scope.
All right. Let's go down to the AwakeFromNib. Now this code you do have, and it's in your outline view, or you can grab that code and paste it in. And I'm going to go ahead and -- quickly type in this code, and then we're going to walk through it. So I'll compile it.
Has everybody got the code copied in? All right. So your code will look a little more like this, that you just pasted in. from this point on down here, make toolbar. It's very much the same code, so this will look similar as we're walking through it, and I'll try to highlight the differences if I can remember them.
All right, so the first thing we do is we're going to make a new toolbar. This is a new object in Tiger for AppleScript Studio, and we use the typical make new, and what type of thing we want is to make a new toolbar, and it has several properties. One of them is the name.
This one's very important. You have to have a unique identifier for your toolbar. In this case, we just call it the document toolbar identifier, and there's various other properties here. Now, you may not understand or know what all the various properties are for your toolbar, so there's actually a resource as part of your project, and if you look in the resources section, there's an AppleScript kit definition, SDEF, and that actually uses our new dictionary viewer that's a part of the script editor as well as... part of Xcode, and what I love about it is it's very simple to find things now, so if I want to learn about a toolbar, I just simply go to the search field, type in toolbar, and I can see that I've got a toolbar class.
Now, I'll zoom this up so you can see a little better all the various properties that a toolbar knows about. So these are the allowed identifiers, default identifiers, we're going to fill that out, what the display mode currently is, our size mode, and whether or not it's visible. So that's all controllable through AppleScript. It's very simple. to use. So I'm going to move back to the code.
[Transcript missing]
Anyone? The window, exactly. So we attach the Awake from Nib handler to the window, and when it gets called, the object is the window. So we are just simply getting the full path to that script view. Now, I actually could have written this, so I didn't even do that.
I could have attached the Awake from Nib to the script view, checked its name, and then assigned the property. And in the entire script, I would never have to say, blah-de-blah of blah-de-blah of blah-de-blah. But just to make this simpler to walk through, I've showed you the difference there.
Okay, now we've got those assigned, and it actually does make one thing here, and it's a call method. And the controller object that we drug in is actually attached to the script view. And I'm using what's known as an Objective-C backdoor for AppleScript Studio. And I've never been so grateful in my life when I added this feature, because it's been one way to work around, you know, things that we didn't have completely covered yet in Studio. So I can always point you to this thing called call method. And what it does is it sends an Objective-C message to the script view and says, give me your controller. And then I just simply send it. save a reference to that.
All right, now let's look at the toolbar items. So I'm making each new toolbar item. And I make it at the end of the existing toolbar items of the DocumentToolbar. Again, the DocumentToolbar was the thing that we just created. And it as well has many different properties. Here's a very important one, the identifier.
Again, this identifier needs to match all the way through. So this is the one for the compile. This is the name that I give it, compile, if I want to refer to that toolbar item in the script. It's actually called compile item. This is the label. This is what the user sees in the toolbar when they have it showing. So that's that label. The palette label also has a different entry.
So you can actually have a different name inside of the customization palette. A tool tip, which in this case is called compile script. That's also dynamically changeable. So script, you could actually change your tool tip as you like. And we have image name and compile script. Now, so for every toolbar item in our toolbar, we want to make sure it has the appropriate icon. So we actually haven't added those yet. So let's go ahead and do that right now before I forget.
And if you'll go into your studio session, There is a section, a folder here called Icon Resources. Okay, so you want to go to the finder, find that Icon Resources folder, and I'm going to simply copy that folder, and I'm going to go to my home directory, and here's the ScriptView project that I'm working on right at the moment, and I'm going to paste those Icon Resources in. So that just copied the folder, put it over into my project on disk. Now I actually needed to add that to Xcode. Let's see if I can zoom in here. Well, it won't work.
So let's, I'm going to grab that Icon Resources folder, and I'm going to drag it under the Resources folder in my project. And when I do that, it simply asks if I should go ahead and create these groups. So I go ahead and click on the Add button.
TIFFs is the preferred, but you can use pings. It should work just fine. So I just happened to have TIFFs from--a lot of these actually come right out of the script editor, so that's what we use there. So I can see that I actually have my compile script TIFF and this has the compile tool. So I'm going to go back to my script. And you can see that all I simply do is I reference that TIFF or that image right here with the image name.
You can actually--there's another property called Image, and you can load your image any other way and just simply set that. But this is the easiest way to do that. So we do that for that. Now here's the new feature in--also in Sight of Tiger. And this is target action. We actually couldn't reuse the word action. We had to call it action method.
Had some symmetry with call method, so it was okay. In Interface Builder, when you wire up like a menu item to an object, you're actually setting up what's called the target action. The message is sent to the target and it sends that particular action. So in Studio, I can do the same thing. I can say that when the user clicks the compile button, so that's the same thing. So I can say that when the user clicks the compile button, so that's the same thing.
So I can say that when the user clicks the compile button, send this method--it's an Objective-C method on that object called compile script. And it sends it to that target. So at this point, I don't have to do anything else with that button. All the code--it'll all be handled for me. I don't have to handle responding to users clicking on that toolbar item. And we do the same thing for the stop. And we do the same thing for record.
[Transcript missing]
Sure. You just write that script, and we'll show how you would do that. Okay, that would be part of that. So let's go ahead and look at the other types. Now, you'll notice that for the standard script editor stuff, it's all doing it with target action.
But the last three that we have here, I don't have target action. It's the same setup for everything else, but there is no target action. And there's another way that we respond to toolbar items that don't have target actions assigned to them. But we'll come back to that in the next step.
And the last thing that we do is that, what is the object again? The window. The tool, the window has a property called toolbar. We need to assign the toolbar to the property to the window. And we just simply say set toolbar of the window, or the object in this case, to document toolbar. So I'm going to go ahead and save this. And we're going to choose, click on the build and run. and see if we made any mistakes. It's not outside the realm of possibilities. It's never happened to me before. It's un-possible.
Okay, so our application runs, and there you go. We've got a toolbar. You can see that I can actually click on... I think I've got it set. Yeah, so I'm going to zoom in here. And I can click on the Customize palette, drag it around, all the standard behaviors. Show/Hide, you can actually use a little trick of clicking on the Option key, I believe.
And we can show and hide it. And we can actually even go ahead into our script editor area, type current date, and click on the compile button. And you can see what it did is it used the target, talked to the script controller, and said compile script. And it took care of all the code for me. Now the cool part is I can click run. And you'll notice that I have a result.
Again, that script controller took care of all that work for me. I didn't have to do a single thing. So with almost very little code, actually all the code was just add the toolbar, I can have a script editor that knows how to do everything that script editor does outside of saving it. So that will take care of that section. So let's go ahead and go back. Quit the application. And we'll take a look at our next step.
Okay, so what did we learn? We learned how easy it is to add icon resources. They could be any image type. I had TIFFs in this particular case. I added a wake from nib handler to the window so that when that document is loaded, I have an opportunity to do something in my script.
Tim Bumgarner Studio is really, really based on that. It's being able to say, "Oh, I want to know when some event happens, when the user does something particular. I want to know when he clicks on something. I want to know when he opens something." You just need to find the right event handler, click on it, and attach it to the right script, and then you'll get called at the appropriate times. So we also looked to see how easy it was to create a toolbar. We do that in script.
And then at the last, we talked a bit about learning about script scopes. Our third step is we need to wire up the rest of the toolbar items. Tim Bumgarner So we only did the toolbar items. Tim Bumgarner So we only did the standard script editor pieces. We need to do the add and delete record and the erase item. And then we're going to hook up our table view so it actually starts to function.
So this is what we're going to do in this step. We're going to modify the wake from nib handler. We're going to attach that handler to yet another object. We're going to add a click toolbar item handler so that this will get called whenever the user clicks on a toolbar item that doesn't already have a target action.
So this is where you'll respond to something happening in your toolbar. And then we're going to add a selections changed handler. We want this to be when the user clicks on the table view, and as they click, we want to update the script source out of that table view. So we're going to wire all that up together and then hook up the data source behind the table view. So let's go back to the hands-on. Is everybody staying with me? Doing all right? OK, cool.
All right. So now, hopefully I don't get lost here in the next step. So let's go back to our-- back into Interface Builder. I'll actually get rid of this palette. I don't need that. And we are going to add an Awake from Nib to our table view. So again, I find it simplest.
to-- see if I can scroll over and see both of these things at the same time-- to just go ahead and select our table view here in the Outline view. It's a lot easier than trying to double-click down into the right view so that I know I have that.
Going to go to the Apple Script panel, which is typically Command 8. It isn't always, unfortunately. So you sometimes will have to make sure you're on the right one. And we see that it's already set up for that. And I'm going to go down to the Nib Group and click on Awake from Nib. And we're going to assign it to the document script. And again, we need to make sure that the scope is set to Nib and not global. All right. Let's go ahead and click Edit.
And what it does is it takes me back to my Wake From Nib handler and selects all the contents, but we're actually going to add something at the beginning of this. And I I get to just hit command period and it just works for me. You'll have to drag it in from your outline document. And that adds some, it's actually a big if else state. And I need to make sure that I have an end if at the bottom of this handler. So I'll go down to the bottom.
And just after the set toolbar, I'm going to type in end if. And then I'll compile that. Hitting the enter key is a shortcut for compiling. And let's go back up and look at the code. So everything that's in the else statement was what we had there before. So we just put a big if block up before that. And we use a technique that also is very common in Studio. Since we actually don't get a different handler for each object, it's using the same handler name.
It's awake from nib. All of the awake from nibs go to this handler that's attached to that script. So what you do is you get the name of the object. That's why it's important to name it. And the first thing we check is we say if the name is equal to script table. That way we know that this particular object that's being called for the awake from nib is the script table. And we again use our reference.
Now, you don't have that reference. I do as I was showing the new technique. But you'll have that there. And we create a new data source. And we do that by simply saying set up our reference, which happens again to be data source, to make new data source at the end of data sources with the property name. So I actually, once I create this, I can always access that particular data source by using it by name.
Now, the next thing we do is create all the data columns. And we make a new data column at the end of data columns of data source. Data columns is an element of data source, and with some various properties. And you'll notice some similarities. We've named each data column to match the name of each table column. So if you misnamed these, they won't be able to find each other, and you'll have data that won't show up in a particular column. So that's a typical thing. So when you build and run your application, you notice that there's a column.
If you have a column missing its data, that's a good clue. Go make sure that you've created the data column with the same name as the table column. And actually, in Tiger, it's even simpler than this. You don't actually have to create a data source, and you don't have to create the data columns. If you have a list of records, an AppleScript list of records, or even a list of lists, you can simply say, set content of table view to that list of records.
And it will create the data source. It creates all the data columns and all the data rows and all the data cells for you. So one call can populate the entire table view. And we're actually going to see how that works a little later. And I do this for all of the data columns. So I have five of them. I have the script date, script name, script source, script result, and script comments.
Now, we actually want this data source to be sorted. We want to be able to click on the various table columns and change the sort order, so we have to tell the data source that it's going to be sorted. By default, it's false. We turn it to true. We want to set the current sort column of the data source to the script date column. So we're going to use the first column for our initial sort column.
And then again, as we've done before, we simply assign the data source, and the object represents What does it represent this time? In this case, it's the table view. So we're in the else block, or the if block, for the table view. So the object is the table view. So we're setting the data source of the table view to this data source that we just created. And the rest of this code is the same. We didn't change it. We just simply put it in an end if.
Okay, so that takes care of our-- setting up the data source. Now we need to actually add a couple more functions down here. So let's go to our handlers. So I'm going to go and I'm going to add-- I missed one. Oh, yes, this is the click handler. Let's go back to Interface Builder.
And we're going to select back to our window. What we need to do is we need to add the handler that's the toolbar click handler so that when users click on a toolbar item that doesn't have a target action, it'll get called. So I select my window, go into AppleScript, and this is actually new for Tiger. There's a group here called toolbar. And there's one called click toolbar item and another one called update toolbar item. We're simply going to work with the click toolbar item.
It's already attached with a document. This particular window is already attached to the document script. And it already has script set to scope to nib. So I'm going to go ahead and save that. And it just means that I have changes left over there. I'll go ahead and accept that.
And I'm going to click the edit button to take me back to the code. And you can see that, again, it added the handler for me. I didn't have to remember what that was. And in this case, I'm going to have to go back one step and paste that code.
[Transcript missing]
Okay. I'll scroll down here a little further. This is all the finished code. And add record. And here, once again, you'll see that in the code that you have, I have this bit of code. I wish it was an easier way to show this together.
[Transcript missing]
and I think I have all of my code, and you should have those three. You should have those three. You should have add record, delete record, and that last one I just showed you should be in your script. We'll save that and build and go.
And what we should be able to do now is run our application. I'm going to type in current date, compile it, run it. And if all is going well, I click the Add Record, it added the record. So there I go. It's just that simple. I'm going to go ahead and type front window.
[Transcript missing]
And I can also check to make sure the Erase button is working, so that just erases my script view. So that takes care of that step.
All right, so what did we learn in step three? We showed how easy it was to implement the click toolbar item handler so that you can respond to toolbar items that don't have a target action. And then we showed you how easy it was to create a data source. And as I explained, it's actually simpler than what I even have in my example.
Okay, we're on to step four. We're closing in on the home stretch, and we're doing good on time, it looks like. So let's look at how to save the document. So we want to be able to save what's in the script view, and we want to save out all of the records that are in that table view. And then we're also going to turn on the column sorting so that we can sort our table view. So we're going to implement the data representation handlers.
There's two of them, and we're going to talk about them in just a moment. And then we're going to have a handler so that it responds to the user clicking on a column in our table view, and that's called the column clicked handler. And then we're going to turn on some sort indicators. It's very simple to do now in Tiger as well. So let's go back to our demo.
I'm going to quit the ScriptView. And let's see. What we need to do is go back into our Document Nib in Interface Builder. Now, by default, all of our templates are still built to work on the oldest-- clear back to like 10.1 and 10.2. So it's set to be global by default, because that's a new feature in Tiger.
So what you want to do is select our document object, which back here in the icon view is the Files Owner. Sometimes that's one other reason I like the outline view. It's much more obvious what that is. It's the document object. And it already has two handlers associated with it.
And they're in the document group. And they're both on by default in this template. One is called Data Representation, and the other one's called Load Data Representation. And you can see that the problem here is it's set to global, and our act would not work correctly if it was trying to reference the wrong script. So I'm going to switch that to Scope Nib. Now, on yours, you will just leave it global, and it'll just work fine for purposes of the demo. Let's go ahead and then look at that. And we'll implement those handlers.
My drive falls asleep in between. All right, let's go here and implement the data representation. Now, this data representation handler is the handler that gets called by AppleScript Studio when it's time to save your document. And what it's asking it for is, what data do you want me to store onto the file for you? And so you can simply return an AppleScript structure of any type, and we'll take that data. And Studio takes care of actually putting the bits out onto disk. And so I'm going to go ahead and implement that.
Hopefully, let's see. Oh, actually, we missed one. We're going to have to go back. I'm going to jump ahead one and implement the data representation. And what it does is it gets some information. Again, it gets the content of the data source. Again, if we compare this to the code that you have, it should be here. And let's go up to the data representation. You can see it's actually quite a bit more code. Again, it's this verbose instance.
But what it's doing here is that before Tiger, what you had to do is if you wanted to get that data source, and all the data out of it, you had to say contents of every data cell of every data row of the data source. And that would, in essence, build up this list of records for you.
With Tiger, it's just as simple as saying, give me the content of that data source. And it will do that much faster for you. We're also going to keep track of what current sort column we have so that the sort column will be kept track of when we save our document. We get the content of the script view. So whatever happens to be in the script view at the time we save, we want to save that out in our document. And it would actually be nice if we saved the bounds of the window.
So wherever the user resized and positioned their window, we'll save those bounds and then we'll restore it so when they open their document, it'll put it back to where it was before. And then what we do is construct a simple Apple script record that has the table view data. It has the name of the sort column, the source, and the window bounds.
And then you simply return that as the result of this handler. Studio takes that data, streams it out to disk for you. So then when it comes time for the user to open your document, it's going to call the load data representation handler and we're going to implement that one. And let's see what this does.
And what it does is what's passed into this is the exact same data. So you see where the with data is? That is this data. It reads it in exactly in the same format that you gave it to Studio, and it gives it back to you in the with data object.
And so it's just a matter of pulling out the bits and pieces out of that data that we want. So to set up the sort column, I get the sort column of the data source to the data column that had that name, sort column name of with data.
So you can see that that was stored right here. Sort column name was in that object. We just pull it back out. Same thing for the script view. We set the content of the script view to the script source. We set the bounds of the window to the window bounds that we've saved.
And here again, this is the real power in Tiger. I didn't have to make and go through the data source and go through and say, okay, for every data row, I need to make a new data row for every data cell, create a new data cell. I simply say set content of the data source to the data that I saved.
I saved out before and it constructs everything for you. It sets up all the data columns and all the data cells and it's very fast. And so the last thing we return is whether or not this succeeded. So if there was some error here, you would return false and you would get the standard alert at the end of the application or when you try to open your document. All right, so that takes care of the data representation. Let's go ahead and add sorting. Actually, let's go ahead and run this. Build and go. And again, we go through the process of typing in some script, executing. I'll do another one for front window.
All right. Oh, I forgot to click Add Record. It might help if I do that. Current date. And let's go ahead and run and add that record. So now I actually have two items in my table view. And just to make sure everything's working well, I'm going to reposition this window. Let's put it way over here. And I'm going to make it a little bigger. And I'm going to go to the Save menu, or File menu, and choose Save. And we're going to just save it on the desktop, and I'm going to call it Sample.
And save that. And you see that it actually gave it a title. If I close the window, go to the File menu, and go to the Open Recent and choose my sample, you can see that it actually loaded the document back up. I get my source that was currently in the view. And I get all the various records that I had in the document. And it also remembered the window bounds where the document was located.
Now one thing we skipped and missed is the fact that when you click on this table view, it should be updating the script source. We missed that step. So we need to go back and add that. So let's go and quit the script view at the moment. We'll go back to Interface Builder.
And we want to select our table view. Again, I'll go to the Outline view in the project window here, select Table View. And I want to know when the selection has changed. That's in the Data View group over in our AppleScript Inspector. And there's one called Selection Changed. And I'm going to save that. And while we're in here, let's go ahead and add the handler for our table view so that we'll know when a user clicks on the column.
So I'm going to select that as well. And again, it's in the Data View. And there's one called Column Clicked. Save that. And let's go Edit and fill these out. So for the Column Clicked-- let's see if I get the right one here. Nope. Yep, that was correct. Let's fill out that handler.
Now, whenever the user clicks on a table column, what they're indicating is they're going to change which one is being sorted on, and if they click on the same one, they're just changing the order from ascending to descending. And so that's all that this code does. This is very standard code.
You could actually just copy-paste this code any time you need to do this sorting in your table view. Hopefully in a future version we'll actually just take care of this for you, so you don't even have to put this code in. It'll just handle it. But for now, you just copy it out of any of the examples. It's all the same.
And we get the name. We check to see if it's the same sort column. If it's not, we're going to switch the sort column. Otherwise, we're just changing the sort order, and we just update the object, which happens to be the table view. Now, the other one that we needed to fill out that we missed was the selection change.
This is whenever the user clicks in the table view, we need to update the contents of the script view. And that one was way back up here, so we missed that quite early. Put that in. And all it does is whenever the user clicks in the table view, we set that to the table view.
And we set the content of the result view to an empty string. And we grab out of our data source the data cell called script source. Remember, we have a column in our data source for the script source. So we go get the value out of that, and then we simply stick it in the script view by saying set content of script view. All right.
Now, the one last thing we need to do for our sorting is to actually add our sort indicators. And if you go back up into the Wake from Nib, and in the first if block, just after you set the data source, It's just a matter of turning on our indicator by doing this. Turn on the sort indicators.
And it's the property called useSortIndicators of tableView. And we just simply set that to true. And that puts the little triangle and keeps track of whether it's ascending or descending order in the sort. And we don't have to worry about trying to set that before, which you had to do that before, Tiger, if you actually wanted sort indicators. So let's build and run this application and see how we're doing.
So once again, actually to save time, I'm just going to go and open up the existing sample so I don't have to type it again. And you'll see that it actually has the sort indicator turned on. And as I click on that, it's changing the sort order. And I can change which column I want to be the primary sort. So sorting is very simple to do. Okay. Let's go ahead and look at the last step here.
and what we did before. So I showed you how to implement the data representation handlers. So any document-based applications, you need to fill those out. It's very simple. Simply get the data you want to save, return it in the data representation handler. And if you want-- and when the document is open, you'll just implement the load data representation. And you're given your data back.
And you can populate your UI from that. And we also showed you how to add column sorting in your table view. Now the last thing we're going to look at is how to debug ScriptView and add a creator code. So if you're using Xcode 2.1, we're going to show the fact that we actually use the new action breakpoints or breakpoint actions. And then we're going to set the creator code in this step. So let's go ahead and do that.
Now, this one you can actually go ahead and grab step five. So I'm actually going to close the existing application or my project. And I'm going to go to my sources. And I'm going to grab step five in the script view. And open up-- now, if you're using Xcode 2.0, you have to use the .Xcode project. If you're using 2.1, you'll open up the Xcode Proj project.
So I'm going to go ahead and open up the script view Xcode Proj, because I can show the breakpoint actions, which is a new feature in Tiger. If you are using 2.0, that's OK. We'll still be able to debug. You just won't have those actions. So I'm going to go ahead and build and run this.
I'm actually going to clean, just to make sure that since it's all been the same project name, I'm going to just clean everything out. And you can do that by choosing it under the build menu, clean or clean all targets. And then I'm going to go ahead and just build the application and run it.
And you'll notice that the first thing I get is an error. So the document window hasn't come up yet. I've got this really, really very informational error here. Everybody understands what NSReceiverEvaluationScriptError means, right? Steve has documented it well, so you can sort of get a hint in the documentation.
He does explain what all these are. We hope that it's actually a long-standing problem. We need to address that, and hopefully they'll be able to take that and have a much more informative error message there. But what we have now is the document does come up, but in essence, something's not going to work very well. So let's go ahead and quit that and go back to Xcode, and we're going to debug this to figure out what the problem is.
So back in Xcode, I click on my scripts group, select my document, AppleScript, and we're going to go down to the Wake From Nib. Let's make this a little wider, easier to see, and zoom that up. And I'm going to go to the Wake From Nib handler. Now, this is a good place to start, because it was very early in the app launch. It was also very early before the document came up.
So Wake From Nib is a very good place to start to debug this process. So I'm going to put a breakpoint here. Now, actually, so for those of Xcode 2.0, you just simply click on the code. You just click on the column over here on the left and put your breakpoint on. If you're using Xcode 2.1, you can hold down the control key on that breakpoint, and you can say edit breakpoint.
And you get this new breakpoints UI. And I'll zoom this up so you can see it a little better. And you can see that it's now put a breakpoint on Awake from Nib on line 79. And if I click this-- and it has a little bit of an Automator UI-- The dogs, they stole our UI.
That's okay. So what we can actually choose is different types of break actions, so when it hits this break point, we can have it do something very interesting. So as Todd also demonstrated this, I'm going to pick the AppleScript, and I can actually enter an AppleScript here, and it will execute when that break point is hit in the debugger. So I'm going to just simply do what I might have actually typed, for those of you debugging in other methods, back in the code itself.
I might say display dialog away from nibs so I know that I got to this point. And I'll compile that, and test it. Looks fine. So that looks good. I'm just going to collapse. Oh, I just deleted it, is what I did. So I'll do this again. It was going so well. No, it's no problem.
Display dialog. Actually, I've got to talk to him and put the actual script view here and not just the simple text view. That would be logical, right?
[Transcript missing]
And if I go ahead and click continue, and just one note in that is if there's a checkbox, and if I say continue and put it in there, it won't even stop in the breakpoint.
What it does is it does the action and then continues. So if you have some tight loop and you don't want to have to keep stepping in the debugger, you can just have it repeat the action, and it just continues running for you. But in this case, the default is not that. It's going to stop in the debugger for us.
And so here I've got my debugger window. And it stopped on the AwakeFromNib handler. And we stepped on the first line, and we actually have different things here. We have all of our variables are global. So there's pi as represented here. These are all the AppleScript globals, which I always find it funny I could actually go in and redefine pi.
Or the number of minutes. If I'm a little late for work, you can put that to be 80 minutes or something like that. It's probably not a good idea to change your globals. But it does show the various properties that are in my script. So in this case, we haven't assigned any of the properties that I had before, like a result view or script view.
And then at last, it shows the local variables. In this case, we actually get to find out what the object is. So we know this time, when the Awake from Nib handler is called, that it's the window that's being passed. So we're going to step. And we'll step over to the next line. And it's going to check the name. And it's not that name.
And it goes down. And it goes into the else statement. It's going to create our toolbar, which is the right path. That looks good. So I don't think there's any error there. So I'm going to continue. And once again, the breakpoint is hit. Because Awake from Nib, we also attach to the table view. And again, it triggers my action. It tells me I'm here. I could have had it say something, for instance, or other interesting things. And I've stepped back into the code, stopped at the first line.
And it's going to check the name. And so I can see that-- oh, the object is the table view. We've got the right object. And the name is script table. And so it's going to compare the name is equal to scriptable. There we go. So we missed a variable, a letter. We actually need that to be script table. So I'm going to stop that.
Because that's pretty obvious that that's going to be the problem. And I'm just going to go ahead and build and run this just for brevity. Let's zoom back up. And there was no error. So that took care of that error. So I'm going to open up my document that I saved before.
And there's actually another bug in here. And I'm going to show you another technique that's very common in debugging your Studio applications. And that's if I click on here. I can click on the name. I can click on the result. But when I click on source, that's a little better error. It says that the variable, the column name is not defined.
So at least it wasn't any of those NS receiver errors. But obviously, something is wrong. Now, with the application still running, what I'm going to do is I'm going to launch script editor. Because again, Studio is a scriptable application, albeit at the view level. But it's still-- the code that I write is the same code I can access from the outside of the environment. And I can go back to my demo monkey and grab this bit of code. So it saves me the trouble of typing it.
And what it does is it talks to the script view application, which is running, by doing a tell block. And I get a reference to my table view. Again, I have to drill down because I'm doing it from the outside. And what I want to do is I want to get the name of every table column. Is that a little suspect? Maybe I didn't have that, because we mentioned before if the name is misspelled or missing, it's going to cause a problem. So I'm going to go ahead and run that.
And it's a little hard to see here, but down at the bottom, you actually see it returns a list of strings. And we've got script date. We have script name. There. You can quit the application. Go back into interface builder. Or actually, we have to go back into Xcode and find our resources. And drag this down.
Well, if I time this just right, you won't be able to ask me any questions. This will be good. Resources. Yeah, that would be nice to have patch and continue, you know, build and continue. It's interesting suggestion. Let's, so I'm gonna go in here and I'm gonna look at the various variables here.
Bring up my Apple Script panel and I can see that I have script date on the first one. I have script name, but certainly, there we go. It's missing the script source. So if I add that, I wouldn't spell it correctly. I'd have to debug it twice. Let's say that.
Go back in here, build and run. Open up our existing example and let's go ahead and you can see there as I click on date, looks good. And source, everything's working. Okay, cool. Well, we're short on time, so I'm gonna skip setting the creator code, but let's wrap this up here.
So, what did we learn today? AppleScript Studio is a very powerful technology inside of, and we've enhanced it for Tiger to make it easier for you, much more powerful, better performance in areas. So that's all built under this framework called AppleScript Kit. It has the better table view support, data sources, and adds things like toolbars.
We've also used OSA Kit, another public framework that we've introduced in Tiger that provides a script view, script controller, so there may be a need in your application to have a simple little script editor that you can use. It's very simple to do. You can do it almost with no code.
Tim Bumgarner So, what did we learn today? AppleScript Studio is a very powerful technology inside of, and we've enhanced it for Tiger to make it easier for you, much more powerful, better performance in areas. So that's all built under this framework called AppleScript Studio. Tim Bumgarner So, what did we learn today? AppleScript Studio is a very powerful technology inside of, and we've enhanced it for Tiger to make it easier for you, much more powerful, better performance in areas. So that's all built under this framework called AppleScript Studio. because there's quite a community there, and people are very helpful.
And thank you very much for those of you that take time to respond and help. And with that all, we've got 10 seconds. So do we want to-- we'll take a couple. See if we can get away with doing a couple. So I'll bring up John Montreon for questions and answers. And oh, yes, they've stuck in, so I don't have to mention. And please give us feedback at that location. Drew's too?