I first read about this on a MacScripter posting asking about this, and then found this excellent tutorial at Guimkie. There are very few differences between my tutorial below and his, but in my own tutorial I have created somewhat more zoomed in screenshots and a bit more information on the creation of appcasts. You might also want to consult the documentation on the Sparkle homepage and the PDF that comes with the download.
1. First download the Sparkle module from its homepage. This tutorial uses Sparkle 1.1 and XCode 3.1.
2. Drag the Sparkle.framework into your XCode application into the folder “Linked Frameworks” of the “Frameworks” folder.
You should now see it in your linked frameworks folder.
Now, from the “Project” menu of XCode, choose “New Copy Files Build Phase” from the “New Build Phase” menu item.
A new window will appear looking like this:
Now, drag the Sparkle.framework from the “Linked Frameworks” folder and drop it onto the newly created “Copy Files” build phase listed under your application in the “Targets” section of your project.
Now in the Info.plist file of your project in XCode, you need to add a new key. This will designate a link to the RSS file you will eventually create, called an “AppCast” which will contain the information about updates to the application. For example:
SUFeedURL
http://foolsworkshop.com/downloads/sparklesample.xml
Now switch to the “Interface Builder” application and your “MainMenu.nib” file (open it from the “Resources” folder of your XCode project if it is not open.
From the File menu choose “Read Class Files”
Navigate to your folder and you should see the Sparkle.framework folder and inside that the “Headers” folder (or actually an alias to the folder, which is deep in the “Versions” folder). Select all the files in the “Headers” folder and add them.
Once you have added the class header files from Sparkle, add an “NSObject” which looks like a blue box from the library panel into the list of files in your MainMenu.nib.
Click on this object and in the “Information” tab looking like a white “I” on a blue circle, type “SUUpdater” into the “Class” field (it should auto complete if you read the class files correctly) and press enter. This will add the required Class Actions in the panel below it.
Now create your “Check for Updates…” menu item in the application menu by dragging an NSMenuItem into the appropriate place. After you add it, you can change the “Title” of your menu in the inspector in the first tab.
Now, you need to connect this menu to the new Sparkle object you created. Control-click on the menu item and a blue line will appear. Drag this line and drop it on the “Updater” object.
See Max Karreth’s tutorial for a bit more on how to add a preference for automatic checks for updates.
Everything you need to do in the project is set up. However, you still need to set up an AppCast RSS file. There is a sample of one in the Sparkle documentation PDF and also you can download the test file used found in the Demo application. I created my AppCast RSS file using the RSS application Feeder which actually has a template for creating Sparkle RSS files (if you use this, consider editing the template and turning on the extra field for “Release info”). The important things that must be included in your AppCast RSS feed are a link to the Sparkle namespace:
xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle"
You then add a new RSS item each time you make a new update, and include an enclosure linking to your new release, which the documentation says should be named something like “Application Name App_2.0.zip”
Here is what my RSS feed looks like after I created it with the Sparkle template in Feeder. Some of these things are optional lines or extra information added by Feeder itself, but it should give you an idea of how this works:
http://foolsworkshop.com/downloads/sparklesample.xml
A simple example AppCast for Sparkle
Feeder 1.5.3(378) http://reinventedsoftware.com/feeder/
http://blogs.law.harvard.edu/tech/rss
en
Fri, 30 May 2008 11:35:15 +0900
Fri, 30 May 2008 11:35:15 +0900
Sun, 01 Jun 2008 11:24:54 +0900
version-20-no-useful-changes-upgrade-for-$100
http://foolsworkshop.com/downloads/sparklesample.html
In addition to the RSS file, you might also want to post some release notes on the new version, which you can see in the above RSS is linked with the “sparkle:releaseNotesLink” tag. If such a file exists, Sparkle will display this file, which is regular HTML, when a new update is found.
You can try all this and play with a sample application here:
Note: Max Karreth has already been nice enough to create a similar sample application but I had some trouble running the application.
Building this application and running should give you a chance to see how Sparkle works, as I have posted a “fake” 2.0 update. Note that the built application is labelled as “2.0” in the Finder if you choose “Get Info” after downloading the update.
I have not been able to find any way accomplish this task in AppleScript. Philip Buckley’s solution uses the Cocoa method “editColumn:row:withEvent:select:” and the “call method” command to get at it (see this earlier posting for more on this)
This method takes four parameters, as his email outlines:
the column index — NB this is zero-based, so first column is 0, second column is 1 etc the row index – NB this is zero-based, so first row is 0, second row is 1 etc an NSEvent — should be nil I think, but for this purpose it seems it will accept pretty much anything, so in the example below, which I have tested, I have pased 0 a boolean — 1 for true
I created a sample XCode Project which implements his solution for others to play with. You can download it here:
The project creates a data source for the main window’s table, fills it with some text in 10 rows, and then provides a button which, when clicked, will select the column and row indicated by the user in two separate text fields.
The key code for the button is below:
set theWindow to main window
set theRow to (the contents of text field "selectRow" of theWindow) - 1
(* I subtract one because the parameters in the Cocoa method used below is a 0-based index *)
set theColumn to (the contents of text field "selectColumn" of theWindow) - 1
(* I subtract one because the parameters in the Cocoa method used below is a 0-based index *)
set theTable to table view 1 of scroll view 1 of theWindow
set first responder of theWindow to theTable
(* If you want the row to also be selected, uncomment the next line *)
(* set selected row of theTable to (theRow + 1) *)
call method "editColumn:row:withEvent:select:" of object theTable with parameters {theColumn, theRow, 0, 1}
(* This example does not error check to see if the inputted row
and column numbers are greater than the total number of rows/columns *)
Many thanks to Philip Buckley who responded to my posting about this problem.
]]>set the first responder of myWindow to text field "secondField" of myWindow
You can download a very simple sample application which shows you how you can respond to the “return” key to move to the next text field. It also has some code to show you a button that, when pressed, will move the first responder to the second field on the screen.
Download the sample XCode project here: First Responder Example
Here is are the key lines of code involved:
on clicked theObject
if the name of theObject is "switchField" then
set myWindow to the window of theObject
set the first responder of myWindow ¬
to text field "secondField" of myWindow
end if
end clicked
on keyboard up theObject event theEvent
set myWindow to the window of theObject
if the name of theObject is "firstField" then
if the character of theEvent is return then
set the first responder of myWindow to ¬
text field "secondField" of myWindow
end if
else if the name of theObject is "secondField" then
if the character of theEvent is return then
set the first responder of myWindow to ¬
text field "firstField" of myWindow
end if
end if
end keyboard up
]]>2. Each file must have an additional META tag added inside the HEAD tag near the top of your HTML files with the title of your application and “Help”:
3. After you have finished making all your help files, open the application “Help Indexer” found in your Developer/Utilities folder. Navigate and choose the folder containing all your HTML, CSS, and images. This will create an “index” for your help files which can be used to search your files in the help browser.
4. Back in XCode, right-click on your “Resources” folder on the left and choose Add – “Existing Files…” choosing your folder with the help files and the newly created index. When you are given some more options, this seems to work for me:
This should result in the files being added to your project, looking something like this:
You then need to add two keys to your “Info.plist” plist file, one indicating the name of your application’s help book, and the other the name of your help folder. In my example, here is what I needed to add:
CFBundleHelpBookName
Help Book Example Help
CFBundleHelpBookFolder
Help Book Example Help
5. Finally, you probably want to change the “Title” of the help menu item in “Interface Builder” to something like “Help Book Example Help” (in my case) so that it doesn’t say “NewApplication Help” when it is run. You can find the help menu item in the “1” menu under “2”
Now try compiling and running your application and the help book’s index.html home page should appear. My biggest complaint with the Help Book browser in OS X is that even simple files seem to load relatively slow; slower than running files directly in Safari for example. I am often reluctant to read help files since the help book takes one or two seconds longer to load than I am willing to wait for an answer. In the same time I can google a question online rather than risk the possibility that the help files are sorely lacking in documentation.
You can download the sample XCode project demonstrating the above here: Help Book Example
In order to write this posting and learn the techniques described here, I depended on these useful websites: a MacScripter posting on the topic and this excellent tutorial in French (I just looked at the pictures and guessed what I could from the accompanying text but the author recommends using Google to translate the site).
]]>Activate the “keyboard up” handler for the text field you wish to detect keyboard entries for and add some code.
When a key is pressed, a numerical Apple “key code” is generated that can be accessed by AppleScript. However, according to AppleScript Studio documentation:
KEY CODE: the hardware-dependent value of the key pressed; you aren’t likely to work with the key code and no constants are currently provided to specify key codes; however, you may want to experiment with possible values; (for example, for at least one keyboard, the key code for delete is 51 and for backspace is 117)
This is not very reassuring and I don’t know how standard the numbers are from keyboard to keyboard.
You can also access the “character” of the keyboard event which is just the literal character. Check the AppleScript document for other properties of the “event” class that may be useful to you, including booleans (true/false values) for things like: “command key down” “option key down” and “shift key down.”
Here is some code that will detect many of the possible keys typed into an input field and then show which numeric Apple key code corresponds to that key.
on keyboard up theObject event theEvent
if the name of theObject is "inputField" then
(* Is this the input field we are typing in? *)
set theKeyPressed to (key code of theEvent)
(* Save the key code into a variable *)
set theCharacterTyped to (character of theEvent)
(* Save the character that was typed *)
if theCharacterTyped is return then set theCharacterTyped to "RET"
(* The return key doesn't show up nicely in the result, so let's
replace it with "RET" *)
if theKeyPressed is not 76 then
(* 76 is the Apple key code for the "Enter" key
- at least on my keyboard *)
set the contents of text field "showResult" of window "sampleWindow" to ¬
theCharacterTyped & "=" & theKeyPressed
return false
(* Returning false will allow the typing to continue without disruption *)
else
(* The "Enter" key was pressed *)
display dialog "You pressed the enter key, I think."
return false
end if
end if
end keyboard up
After checking to see if the user is typing into the input field (which they obviously are in a window that has only one text field receiving this handler), the key code and character of the event are put into a variable for later use (some will simply refer to this directly rather than putting it into a variable first). It then checks to see if the character typed is the return key and changes the variable to “RET” so it will show up easier in the output. The code then checks to see if the enter key was pressed (on my keyboard at least) and if not, displays the character pressed, an equals sign, and the corresponding key code. If it thinks the enter key was pressed (if your keyboard also has 76 set to “enter”) then it will display a dialog to that effect. Returning false allows the user to type undisturbed by the events. Set this to “true”, if you like, in order to see what happens to the typed text.
You can download the sample code to try this out here: Keyboard Input Sample
In the case of my own application, I’m looking for the user to press the “return” (key code 36 on my keyboard) or “enter” keys (key code 76) and if this is caught, I will “set the first responder” (see upcoming posting) to the next field I want the user to type into, as if they had pressed the “tab” key.
]]>When you want to write some code for a button press, a menu selection, respond to a keyboard event, etc. in Interface Builder you must explicitly lay out your intentions by activating the event handler in question. For example, if you want to do something in response to the user pressing a key in a text field (see next posting), then:
1. Click on the text field in Interface Builder.
2. Open the AppleScript tab of the inspector.
3. It is good practice to give your object a name here, which can be used to refer to the object in your script.
4. Choose your applescript that you want to attach to this object in the “Script” pop-up menu here.
5. Activate the check mark next to “keyboard up” in the “Key” section of the “Event Handlers” pane.
Forgetting to give an object a name, forgetting to assign it to a script and activate the correct event handler are common mistakes I have made that prevented me from getting any results.
A handy shortcut: You can directly jump to the empty method created by activating the handler by double-clicking the relevant handler.
]]>If, for example, you wanted to use the existing Cocoa method to make a string all uppercase you could write code for a button that contains something like this:
on clicked theObject
if the name of theObject is "makeUppercase" then
set contents of text field "inputField" of window "myWindow" to call method "uppercaseString" of (contents of text field "inputField" of window "myWindow")
end if
end clicked
If, instead, you wanted to have a string only capitalize the first letter of each word, then you would use the Cocoa function “capitalizedString” instead.
set contents of text field "inputField" of window "myWindow" to call method "capitalizedString" of (contents of text field "inputField" of window "myWindow")
You can download an example project with this example here: Call Method Example.
A full list of the Cocoa methods for the NSString class in Cocoa can be found in Apple document NSString Class Reference. Some of these methods need to be handled differently as they may require parameters etc. There is more detail on the call method command in the AppleScript Studio documentation to be found where you can learn more about how to include parameters.
Strings are only a simple beginning, this command opens up a lot of possibilities for using Cocoa methods that may not have equivalents in AppleScript, if done with care.
]]>Apple’s Mailing List for AppleScript Studio:
AppleScript-Studio Home
AppleScript-Studio Archives
It is also great to see interesting interventions from people such as the author Matt Neuburg and many other experienced scripters that I have seen replying with some of the best posts at MacScripter.
]]>on clicked theObject
if the name of theObject is "doMenuItem" then
tell menu item "menuItemName" of menu "menuFile" of main menu to perform action
end if
end clicked
]]>/Developer/Examples/AppleScript Studio/Simple Toolbar
For Leopard users who don’t mind building applications that require OS X 10.5 or higher, you can now create toolbars directly in Interface Builder with the NSToolbar class.
Add the class to your window, and you will get a series of default buttons. You can add buttons to the toolbar by adding NSToolbarItem (the item to the right with the “?” image in it) and can add images for the toolbar via a popup menu in the inspector.
The Simple Toolbar sample scripts controlled the toolbar buttons through the “clicked toolbar item” handler of the window containing the toolbar, which confused me when I tried to use NSToolbar without generating the toolbar directly in the applescript. After much frustration, I discovered that the toolbar buttons were scripted through the “clicked” handler as any other button in the window might be. There appears to be no need to necessarily use “clicked toolbar item” at all.
UPDATE: I posted to MacScripter on a problem I had with buttons that are added or re-added when the toolbar is customized: NSToolbar error when customizing the toolbar
UPDATE: Another MacSripter posting by regulus6633 points to problems using the new toolbar. Apparently there are problems when referring to any non-button objects on the toolbar (such as pop-up menu or a search field). My own tinkering confirms this.
]]>on choose menu item theObject
if the name of theObject is "myMenuItem" then
display dialog "You chose my new menu item."
end if
end choose menu item
]]>Then go back to your script and you can begin scripting the button in XCode. For example:
on clicked theObject
if the name of theObject is "myButton" then
display dialog "You pushed a button."
end if
end clicked
]]>set contents of text field "myTextField" of window "myWindow" to "Hello, World."
Make sure the “name” (not the “title”) of your target object (in this case “myTextField”) is correct in your NIB file in Interface Builder.
]]>
tell every window to center
I used this tip to figure out how to automatically center my splash window when the application first opens:
on will open theObject
if the name of theObject is "homeWindow" then
tell theObject to center
end if
end will open
This gets called before the window displays.
]]>I am only an amateur when it comes to programming and I am new to applescript. However, when I’m not doing my historical research for my PhD dissertation, I sometimes get in the mood to tinker with coding as a form of stress release and recently I have been trying to write an application using Applescript Studio, which is now simply a part of XCode (I’m using XCode 3.1 on Leopard).
I will use this weblog to organize some of the useful advice and sample code that I have come across while trying to learn the applescript language but especially how it is applied to developing applications in AppleScript Studio/XCode.
There are some wonderful resources out there for learning applescript and applescript studio. Below are some that I have found useful.
Apple Documentation
Chief among them is Apple’s own excellent documentation:
Applescript Studio Programming Guide
Applescript Studio Terminology Reference
Samples
The applescript studio samples that can be found on your hard drive if you have the development tools installed are fantastic:
Applescript Studio Sample Applications
There are also really useful samples available at JNSoftware. Click on the various links at the bottom left, and also see his list of miscellaneous project files.
MacScripter
The best one stop location on the internet for information about applescript and applescript studio are the forums of MacScripter.
AppleScript OS X Forum
ApplesScript Studio Forum
MacScripter Code Exchange
Please search the Apple documentation and their forums before posting them a message. They understandably get annoyed when newbies waste their time with simple questions that are answered well in the help files, the sample applications, and in countless previous postings on the forums.
If you find the forums useful, then do them a favor and support MacScripter with a donation. It is a truly amazing resource.
AppleScript Studio/XCode Tutorials
Cocoa Dev Central Applescript Studio Tutorial
Technological Supernova Applescript Studio Tutorial
Referring to Objects in Applescript Studio
MacTech AppleScript Studio: Implementing Preferences System
Create a Browser in AppleScript Studio
Books
I have only read one book on AppleScript but I have found it to be excellent. Consider reading:
AppleScript: The Definitive Guide, 2nd Edition
by Matt Neuburg (2006)
In the posts to come on this weblog, I will include little snippets of code I found through MacScripter, documentation, sample code, other websites, or more unlikely, that I came up with myself.
]]>