Some of you may have found that finding and referencing a specific element in GUI scripting is tedius.
For instance, a reference to a Finder file depends on the status of its Finder window (toolbar visible etc.)
Prefab UI Browser and similar utilities browse the overall hierarchy but do not offer a global search.
This script searches for a specific string in all of an application GUI elements.
However, this is not without (timeout, memory) issues…
You’re invited to test this out and improve this script:
-- GUIfinder rev. 0.5 17-10-2005 by Eelco Houwink,.
tell application "System Events"
get system attribute "sysv"
if result is greater than or equal to 4144 then -- 4144 is Mac OS X 10.3.0
tell application "System Events" to get UI elements enabled
if not result then
tell me to (display dialog "Enable UI scripting in Universal Access" buttons {"OK"} default button 1 with icon 2)
tell application "System Preferences"
activate
set current pane to pane "com.apple.preference.universalaccess"
end tell
return
end if
end if
set Appz to name of application processes --whose visible is true
set fApp to some application process whose frontmost is true
beep
tell me to set mainTarget to (choose from list Appz with prompt " Search in GUI elements of:" OK button name "Select")
if mainTarget is false then return
set mainTarget to item 1 of mainTarget
tell me to set searchterm to text returned of (display dialog "What to search for:" default answer "Apple" buttons {"Cancel", "OK"} default button 2 with icon 2)
beep
tell me to set doAppleMenu to button returned of (display dialog "Include Apple-menu.?
(may take longer and result in memory problems)" buttons {"Yes", "No"} default button 2 with icon 2)
set {totNames, totUIs} to {{}, {}}
tell process mainTarget
set Mainlist to (get UI elements)
set mainnames to {}
repeat with h from 1 to number of items in Mainlist
set hName to (class of item h of Mainlist & " " & name of item h of Mainlist) as string
try
if name of item h of Mainlist = "" or name of item h of Mainlist = " " then set hName to (class of item h of Mainlist & " " & h) as string
on error
try
set hName to (class of item h of Mainlist & " " & h) as string
on error
set hName to ("resource item " & h) as string
end try
end try
set mainnames to mainnames & hName
end repeat
beep
tell me to set selResources to (choose from list mainnames with prompt " Search in:" OK button name "Select" default items item 1 of mainnames with multiple selections allowed)
if selResources is false then return
set searchResources to {}
repeat with doResource in selResources
set x to my getIndex(doResource as string, mainnames)
set founditem to item x of Mainlist
set searchResources to searchResources & {founditem}
end repeat
repeat with a from 1 to number of items in searchResources
set thename to name of (item a of searchResources)
try
if thename = "" then set thename to a
on error
set thename to a
end try
try
say (class of (item a of searchResources) & " " & thename) as string
end try
set aUIs to (item a of searchResources)'s UI elements
set totUIs to totUIs & aUIs
if aUIs ≠{} then
set aUIname to name of (item a of searchResources)'s UI elements
set totNames to totNames & aUIname
repeat with b from 1 to number of items in aUIs
if b = 1 and doAppleMenu = "No" and item 1 of aUIname = "Apple" then -- skip Apple menu
else
set bUIs to (item b of aUIs)'s UI elements
set totUIs to totUIs & bUIs
if bUIs ≠{} then
set bUIname to name of (item b of aUIs)'s UI elements
set totNames to totNames & bUIname
repeat with c from 1 to number of items in bUIs
set cUIs to (item c of bUIs)'s UI elements
set totUIs to totUIs & cUIs
if cUIs ≠{} then
set cUIname to name of (item c of bUIs)'s UI elements
set totNames to totNames & cUIname
repeat with d from 1 to number of items in cUIs
set dUIs to (item d of cUIs)'s UI elements
set totUIs to totUIs & dUIs
if dUIs ≠{} then
set dUIname to name of (item d of cUIs)'s UI elements
set totNames to totNames & dUIname
repeat with e from 1 to number of items in dUIs
set eUIs to (item e of dUIs)'s UI elements
set totUIs to totUIs & eUIs
if eUIs ≠{} then
set eUIname to name of (item e of dUIs)'s UI elements
set totNames to totNames & eUIname
repeat with f from 1 to number of items in eUIs
set fUIs to (item f of eUIs)'s UI elements
set totUIs to totUIs & fUIs
if fUIs ≠{} then
set fUIname to name of (item f of eUIs)'s UI elements
set totNames to totNames & fUIname
repeat with g from 1 to number of items in fUIs
set gUIs to (item g of fUIs)'s UI elements
set totUIs to totUIs & gUIs
if gUIs ≠{} then
set gUIname to name of (item g of fUIs)'s UI elements
set totNames to totNames & gUIname
repeat with h from 1 to number of items in gUIs
set hUIs to (item h of gUIs)'s UI elements
set totUIs to totUIs & hUIs
if hUIs ≠{} then
set hUIname to name of (item h of gUIs)'s UI elements
set totNames to totNames & hUIname
end if
end repeat
end if
end repeat
end if
end repeat
end if
end repeat
end if
end repeat
end if
end repeat
end if
end if
end repeat
end if
end repeat
set founditems to {}
set foundNamez to {}
repeat with i from 1 to number of items in totNames
if searchterm is in ((item i of totNames) as string) then
set foundNamez to foundNamez & item i of totNames
if get {item i of totUIs} is not in founditems then set founditems to founditems & {item i of totUIs}
end if
end repeat
if founditems = {} then say "nothing found"
set foundNamez to {}
repeat with jj in founditems
try
if name of jj ≠"" then set foundNamez to foundNamez & name of jj
end try
end repeat
beep
tell me to activate
if foundNamez = {} then
tell me to display dialog "Nothing found..!" buttons {"OK"} default button 1 with icon 1
return ""
end if
tell me to set selectedNames to (choose from list foundNamez with prompt "Found in " & number of items of totNames & " items:" OK button name "Select" with multiple selections allowed)
set selecteditems to {}
repeat with selectedName in selectedNames
set x to my getIndex(selectedName as string, foundNamez)
set founditem to item x of founditems
set selecteditems to selecteditems & {founditem}
end repeat
end tell
end tell
return {selectedNames, selecteditems}
on getIndex(i, l)
repeat with n from 1 to count l
if l's item n is i then return n
end repeat
0
end getIndex