-
Cocoa Scripting: Properties with Multiple Data Types
The SDEF (Scripting Definition) XML dictionary format allows you to define properties that have multiple data types. This allows applications to support the as parameter to the AppleScript Get command. However, Cocoa Scripting does not fully support the notion of properties with multiple data types. This article describes how to implement multiple data type support using Cocoa Scripting.
####Why Do This?
Before I get into the code, let me briefly describe why you might want to do this in your application. Simply put, the value of certain properties may be expressed in difference data types. For example, you might have a selection property. Lets say that by default, the selection property returns the selected text in your application. However, you may also want to allow the user to ask for a reference to the location of the selected text:
get selection --> "Hello World" get selection as string --> "Hello World" get selection as reference --> word 2 thru 3 of document 1
When the scripter tries to alter the selection, they may do it in two ways:
set selection to "Goodbye" --> Replace the selected text with "Goodbye" set selection to word 1 of document 1 --> select the first word
CAUTION: please use multiple data types correctly. The value returned for each data type should represent the same value, but in different ways. Correct use of multiple types avoids the need to have multiple versions of a given property in your dictionary, each returning the same value expressed in a different way.
####The SDEF
Here’s a snippet from an SDEF defining a selection property that supports two data types: text and specifier.
####Supporting Set Operations (Easy)
Cocoa Scripting facilitates Set operations for properties with multiple types. It will convert the incoming AppleEvent data to an instance of NSString for a text value or an instance of NSScriptObjectSpecifier if the value is an object reference (specifier). Here’s how you might implement the setAESelection: accessor:
- (void) setAESelection:(id) value { if ([value isKindOfClass:[NSString class]]) { // replace the selected text with the incoming value } else if ([value isKindOfClass:[NSScriptObjectSpecifier class]]) { // change the selection to the range of text specified in the // incoming object specifier } }####Supporting Get-As Operations (A Little Harder)
Here is where Cocoa Scripting leaves you to your own devices. The problem is that the desired data type is not passed to the accessor function. You have to get this from the current AppleEvent yourself. I use this function:
DescType FSRequestedTypeForCurrentEvent() { NSAppleEventDescriptor* event = [[NSAppleEventManager sharedAppleEventManager] currentAppleEvent]; NSAppleEventDescriptor* requestedType = [event descriptorForKeyword:keyAERequestedType]; if (requestedType) return [requestedType typeCodeValue]; else return typeBest; }Then, the Accessor can be written like this:
- (id) AESelection { switch (FSRequestedTypeForCurrentEvent()) { case typeBest: // the default if no 'as' parameter specified case typeText: case typeUnicodeText: // return an NSString instance containing the selected string break; case typeObjectSpecifier: // return an NSScriptObjectSpecifier instance describing the // location of the selection break; default: // unsupported type [[NSScriptCommand currentCommand] setScriptErrorNumber: errAEWrongDataType]; return nil; } }NOTE: I generally have AppleEvent specific accessors for use with Cocoa Scripting that in turn use my bindings compatible accessors. This is because Cocoa Scripting needs to support things like multiple data types, and reports errors in a different way.
-
We Need a Scripting User Interface Evangelist
I had an epiphany at this year’s WWDC while listening to John Geleynse’s User Interface design talk. We need someone to evangelize Scripting Interface Design with the same passion and clarity that John Geleynse brings to Graphical User Interface design on the Macintosh.
During the course of his talk John gave a compelling series of examples, tips and references that left me believing that I could improve the UI of my products, despite the small size of my organization. Even more importantly, he clearly demonstrated the difference between a good and a bad graphical user interface, and the consequences of bad User Interface design for the user.
Because this year’s WWDC was largely a repeat of last year, I spent more time in the introductory AppleScript, Automator and Cocoa Scripting sessions than I normally would. I left these sessions with the impression that developing a scripting interface was a difficult and error prone exercise. The Q&A questions at the end of these sessions confirmed for me that the audience was not clear on how to proceed. Everything that was said in these presentations was technically accurate, but I came away uninspired.
Interestingly, I believe that the issues John Geleynse so ably discussed (user centered design, identifying objects and tasks that matter to the user, knowing when to use certain widgets, etc.) are the very same issues that a Scripting User Interface designer must consider.
Several years ago, Cal Simone tried to fill this role. Cal and I differed on the specifics, but it has to be said that he was effective at motivating developers to “do the right thing”, and at keeping Apple focused on the problem. Since Cal left the scene, Apple has been left to do this for itself and it has not really risen to the challenge.
Scripting User Interface design is not about Cocoa, Cocoa Scripting, Objective-C, or even AppleScript. It’s about designing a programatic interface for an application that mirrors the user’s view of the application’s data model and functionality. Very often the user’s view of the application is not the same as how the application works internally.
There are features of Leopard that are going to make each application’s scripting user interface much more prominent (my NDA with Apple prevents me from giving specifics), and so this issue is going to become more important as time goes on.
Developing a Scripting User Interface is not that hard. I’ve built some large scripting interfaces over the years (Illustrator 7/8, Visualizer, Script Debugger 3, and now FaceSpan 5), and there is a method to it. But you need to approach it with as much care and forethought as you do with your Graphical User Interface design.
Apple’s Tech Note 2106 is a start, but it does not go far enough. This document is too much about code and not enough about process. For instance, It does not give a methodology for developing a scripting user interface.
Somehow developers need to be made to understand the why and the how of designing and implementing a compelling Scripting User Interface. As Brent Simmons once said, designing User Interfaces for the Mac is the “The Show”. If you are going to play, do it well.
Finally, I think Scripting User Interface design should be considered when scoring entrants in Apple’s Software Design Awards.
subscribe via RSS