AppleScript_ The Definitive Guide - Matt Neuburg [254]
AppleScript Studio Scriptability
It is natural to wonder whether an AppleScript Studio application is scriptable. The news here is something of a mixed bag.
AppleScript programmers who are accustomed to writing applets, which are inherently scriptable, will be disappointed to learn that AppleScript Studio applications are not scriptable in quite the same easy way. The mere presence of a top-level entity in an applet's script makes the applet scriptable with respect to that entity, but no such thing is true of an AppleScript Studio application. So, for example, you cannot simply tell our SearchTidBITS application to displayResults( ) (see Example 27-7). The problem is that an AppleScript Studio application is not merely an application shell wrapped around a script; it's a true Cocoa application. So your message isn't magically routed to the correct script, because in the way stands the entire mechanism of a Cocoa application.
On the other hand, an AppleScript Studio application is scriptable with respect to the entire AppleScriptKit.sdef dictionary, which is actually visible to users though a script editor application as if it were your application's own dictionary. This means that whatever built-in commands you can give from within the code of an AppleScript Studio application, a user can give from outside it. For example:
tell application "SearchTidBITS"
activate
tell window "search"
tell matrix 1
set content of cell 1 to "AppleScript"
set content of cell 3 to "Matt Neuburg"
end tell
tell button 1 to perform action
end tell
end tell
That's exactly the same as if the user had typed values into two of the text fields and then pressed the Search button! Initially this may sound exciting, but most AppleScript Studio programmers ultimately regret that things work this way, for the following reasons:
It's messy.
The user who looks at your AppleScript Studio application's dictionary sees the entire confusing AppleScriptKit.sdef dictionary, which says nothing as to your application's purpose or what the user can appropriately do when scripting it.
It's overly free.
The user can do things to your application that a user really shouldn't be able to do. To give a simple example, if an interface element is tied to a script, that script is available through that interface element; the user can get its script, and even worse, can set its script. For example:
tell application "SearchTidBITS"
script s
end script
set the script of button 1 of window "search" to s
end tell
That code disables the Search button; its functionality has been replaced, and the only way to restore it is to quit the application and start it up again.
It's incomplete.
The user can manipulate the interface, but can't call any event handlers. You'll notice that in the earlier example it was possible to press the Search button programmatically because there is a perform action command, but it is impossible to tell the application to clicked:
tell application "SearchTidBITS"
clicked button 1 of window "search"
-- error: SearchTidBITS got an error: NSReceiversCantHandleCommandScriptError
end tell
You might wonder, as you can get the script of an interface element, whether it might be possible to route a message to that script. This is a clever idea, and at first it looks promising:
tell application "SearchTidBITS"
set s to (get script of button 1 of window "search")
tell s
urlEncode("hi there") -- "hi+there"
end tell
end tell
It turns out, however, that when you get the script of an interface element, it's a copy. The real script object, the one that the interface element is actually using at that moment, was copied and loaded when the application started up; what you've got is a different script object, completely unbound from its proper context in the running application—for example, its top-level entity values are not the same as the current