After reading Cocoa Programming for Mac OS X by Aaron Hillegass I discovered that I can easily enhance the functionality of my AppleScripts with foundation tools.
Foundation tools are scripts written in Obj-C who can make use of the Cocoa frameworks, which provide complete access to the full power of the operating system of our choice.
For example, a foundation tool can enable you to query the content of the Dictionary application, to directly create PDF files with Quartz 2D or to manipulate movies with the QTKit.
Now, something I always wanted to do was to dynamically display system icons for certain file types with the «display dialog» command, but without having to put all the different icons into the script bundle. I mean, all the icons are already available on every Mac OS X installation, so why blow the script’s size? Plus, some users may use different icons than the standard icons provided by the system:
So finally I wrote myself a tiny foundation tool to incorporate this functionality into my AppleScript projects. It’s just so much nicer to have the proper icon in an error or informational message:
And here is how it works:
Starting with Mac OS X 10.3 Apple introduced Uniform Type Identifiers (UTI) to identify a particular file type. For example, the UTI «public.html» identifies HTML files, the UTI «com.microsoft.word.doc» identifies a Microsoft Word document. If you want to get an overview of available UTIs, then please point your browser to this URL.
The UTIs can also be used to obtain the icon currently used for a certain file type. For this, you need to use the NSWorkspace class that features an iconForFileType method, which returns an image containing the icon for files of the specified type.
Once you have the image data for the icon, you can convert it to the TIFF format and finally create an ICNS icon file using tiff2icns on the command line. And that’s all the small foundation tool is doing: Get the image data for a certain Uinform Type Identifier, convert it to a TIFF file and finally create an ICNS icon file from the TIFF data.
If you want to try it on your own Mac, then I invite you to download the sample project right here:
Please note that the script requires at least Mac OS X 10.4. It was successfully tested on Intel & PowerPC based Macs.
The source code of the (most simple) foundation tool can be studied here. A compiled version of the utility can be found in the sample project.
Merry Christmas!
Important: Opening and saving the below script code in Script Editor won’t result in a usable AppleScript! That is because the AppleScript internally relies on a foundation tool, which is located inside its Script bundle. Therefor please download the complete script here.
-- author: Martin Michel
-- created: 23.12.2008
-- version: 1.0
-- requires:
-- ¢ Mac OS X 10.4 or later
-- tested on:
-- ¢ Mac OS X 10.5.5
-- ¢ Intel & PowerPC based Macs
-- For a list of Uniform Type Identifiers please visit:
-- http://developer.apple.com/documentation/Carbon/Conceptual/understanding_utis/utilist/chapter_4_section_1.html#//apple_ref/doc/uid/TP40001319-CH205-CHDIJFGJ
property mytitle : "UTIcon"
-- main handler called when the script is opened with a double-click
on run
try
set UTI to my askforUTI()
-- user canceled...
if UTI is missing value then
return
end if
set icnsfilepath to UTIcon's geticnsfilepath(UTI)
if icnsfilepath is not missing value then
tell me
activate
display dialog "On the left you can see the icon returned for the «" & UTI & "» UTI." buttons {"OK"} default button 1 with icon (POSIX file icnsfilepath) with title mytitle
end tell
-- calling the flush() handler removes all temporary ICNS icon files created
UTIcon's flush()
end if
on error errmsg number errnum
tell me
activate
display dialog "Sorry, an error occurred:" & return & return & errmsg & return & "(" & errnum & ")" buttons {"OK"} default button 1 with icon stop with title mytitle giving up after 30
end tell
end try
end run
-- I am asking the user to choose a Uniform Type Identifier (UTI)
-- If the user cancels, I return «missing value»
on askforUTI()
set UTIs to {"com.microsoft.word.doc", "public.php-script", "public.png", "com.apple.applescript.script", "com.apple.colorsync-profile", "com.adobe.pdf"}
choose from list UTIs with prompt "Please choose an UTI:" OK button name "Select" cancel button name "Cancel" with title mytitle without multiple selections allowed and empty selection allowed
set usrchoice to result
if result is not false then
set UTI to item 1 of (usrchoice as list)
return UTI
else
return missing value
end if
end askforUTI
script UTIcon
-- list to save the paths of the created ICNS files,
-- so that we can remove them later on
property tempfilepaths : {}
-- I return the file path of the icon for the given UTI
on geticnsfilepath(UTI)
set foundtoolpath to ((path to desktop as Unicode text) & "uticon")
-- set foundtoolpath to ((path to me as Unicode text) & "Contents:Resources:uticon")
if not _itempathexists(foundtoolpath) then
error ("Could not locate the uticon foundation tool supposed to be at:" & return & return & "«" & foundtoolpath & "»")
else
set foundtoolpath to quoted form of POSIX path of foundtoolpath
end if
set command to foundtoolpath & " " & UTI
try
set icnsfilepath to (do shell script command)
set end of tempfilepaths to icnsfilepath
return icnsfilepath
on error
return missing value
end try
end geticnsfilepath
-- I remove all temporary ICNS files created
on flush()
repeat with tempfilepath in tempfilepaths
set command to "rm " & quoted form of tempfilepath
try
do shell script command
end try
end repeat
end flush
-- Iindicate if an item exists at the given path
on _itempathexists(itempath)
try
set itemalias to itempath as alias
return true
on error
return false
end try
end _itempathexists
end script