It shouldn't be, but the tell application block is a stumbling block, right at the start of drafting an applescript.
On my system, for example,
tell application "OmniFocus"works, but
tell application "OmniOutliner"fails, and so does
tell application "OmniGraffle"Not only do you have to memorize some slightly arbitrary and inconsistent elaborations like:
tell application "OmniOutliner Professional"but these references stop even very simple and general scripts from working across variants and versions of the same app (Professional versus vanilla, Ver. N versus Ver. N + 1)
tell application "OmniGraffle Professional 5"
Apple did introduce an improvement around OS X 10.5. Developers, they argued, are unlikely to change an application's 'bundle identifiers' and 'creator codes' across successive versions, whereas they do have a habit of changing its name, and so they introduced the format:
tell application id "com.omnigroup.OmniGrafflePro"which looked promising because it didn't contain a version number.
And thus I personally generally switched to forms like:
tell application id "com.omnigroup.OmniFocus"Which was fine, until I learned that the new AppStore versions have variant bundle names like com.omnigroup.OmniFocus.appstore and therefore choke on any applescript which starts with a line like the one above ...
So do we sigh and return to things like:
tell application "OmniGraffle Professional 5" ?This makes sense if code is genuinely version-specific, but is frankly annoying in the numerous cases where the code for OmniOutliner and OmniOutliner Professional, or Omnigraffle vanilla, professional, or version whatever you like, would actually be identical ... (Two versions of OmniOutliner in the same office, professional and plain, and a need for a simple script which would run on both, for example).
This is why I am generally switching to a third application reference variant, which uses tell application id + creator code. Thus, for example:
tell application id "OOut"for any version of OmniOutliner, and
tell application id "OGfl" for any version of OmniGraffle.I have even adopted the reflex of
tell application id "sevs"in place of
tell application "System Events"All very well, but how do you learn and remember all these four-letter codes ?
Here is a script which will show you the four-letter creator codes (and the longer bundle identifiers) for all the applications currently running on your system. If you want, you can enter a search string, to filter down the list.
It will place a creator code (or bundle identifier) tell application block, for a selected application, in your clipboard.
(Ver .04 below should be compatible with LaunchBar and Keyboard Maestro. Tap space bar to pass a search string to it directly from LaunchBar).
Code:
-- Get creator codes and bundle identifiers for tell applications blocks -- (for applications currently running -- Ver .05 Compatible with LaunchBar - select script, tap space bar and enter string in Launchbar property pTitle : "Tell application id ..." property pDefaultSearch : "omni" property pCodeCopy : "Copy creator code" property pBundleCopy : "Copy bundle identifier" property pNameCopy : "Copy app name" -- System Events on run tell application id "sevs" activate set strSearch to text returned of (display dialog "Enter part of application name: (or leave blank to see all running applications)" default answer pDefaultSearch with title pTitle) end tell handle_string(strSearch) end run on handle_string(strSearch) tell application id "sevs" if (strSearch ≠ "") and (strSearch ≠ "*") then set {lstCode, lstBundle, lstFile} to {creator type, bundle identifier, file} of (application processes where name contains strSearch and bundle identifier is not missing value) set strPrompt to "Applications with \"" & strSearch & "\" in their name:" else set {lstCode, lstBundle, lstName, lstFile} to {creator type, bundle identifier, name, file} of (application processes where bundle identifier is not missing value) set strPrompt to "All currently running applications:" end if repeat with i from 1 to length of lstCode set varFile to item i of lstFile if varFile ≠ missing value then set strName to (name of item i of lstFile) else set strName to item i of lstName end if set item i of lstCode to item i of lstCode & "=" & item i of lstBundle & "=" & strName end repeat set my text item delimiters to linefeed set strApps to lstCode as string set lstApps to paragraphs of (do shell script "echo " & quoted form of strApps & " | sort -t '=' -k 3") if length of lstApps > 0 then set lstDefault to {first item of lstApps} else activate display alert "No running apps have names matching " & strSearch return end if activate set varChoice to choose from list lstApps with prompt strPrompt default items lstDefault with title pTitle if varChoice is false then return set my text item delimiters to "=" set {strID, strBundle, strName} to text items 1 thru 3 of first item of varChoice set {blnCode, blnBundle, blnName} to {true, true, true} -- CREATOR CODE if strID ≠ "????" then set strCode to "tell application id \"" & strID & "\"" else set blnCode to false set strCode to strName & " has no creator code ..." end if -- BUNDLE IDENTIFIER if strBundle ≠ "missing value" then set strBundle to "tell application id \"" & strBundle & "\"" else set blnBundle to false set strBundle to strName & " has no bundle identifier" end if -- APPLICATION NAME if strName ends with ".app" then set strName to text 1 thru -5 of strName set strAppName to "tell application \"" & strName & "\"" else set blnName to false set strAppName to "" end if set strChoice to "CREATOR CODE: " & strCode & " BUNDLE IDENTIFIER: " & strBundle & " APP NAME: " & strAppName set lstBtns to {} if blnName then set end of lstBtns to pNameCopy if blnBundle then set end of lstBtns to pBundleCopy if blnCode then set end of lstBtns to pCodeCopy set lngButtons to length of lstBtns if lngButtons > 0 then set strClip to "-- " & strName & return activate set strBtn to (button returned of (display dialog strChoice buttons lstBtns default button lngButtons with title strName)) if strBtn = pCodeCopy then set strClip to strClip & strCode else if strBtn = pBundleCopy then set strClip to strClip & strBundle else set strClip to strAppName end if set the clipboard to strClip & return & return & "end tell" else activate display alert strName & " is not a scriptable process" end if set my text item delimiters to space end tell end handle_string
Last edited by RobTrew; 2011-05-27 at 11:19 PM.. Reason: Ver 0.3 - Will get its search string from LaunchBar