Find disk items by name

Rather annoyingly, in Tiger, the Finder’s “Find.” function no longer defaults to finding items by name. You have to click the pop-up menu currently showing “Kind” and select “Name” from the list. This GUI script is a simple attempt to automate that. It asks for some search text, opens a “New Search” window, selects “Name” in the pop-up menu, and enters the search text in the text field that appears. The search domain (Servers, Computer, Home, or Others.) is whatever you used last time, but you can click the relevant button yourself to narrow or broaden the search. I think it’ll work whatever your preferred display language, but switching languages to test this has screwed up the search function in my Finder. :frowning: But that’s not the script’s fault. :slight_smile:

-- Intended for Tiger only.
-- Uses GUI Scripting.

on findByName()
	set searchText to text returned of (display dialog "Search for disk items whose names contain." default answer "")
	
	tell application "System Events"
		tell application process "Finder"
			set frontmost to true
			-- The "New Search" window will be the frontmost one _behind_ any floating windows.
			set searchWindow to a reference to window ((count (windows whose subrole is "AXFloatingWindow")) + 1)
			-- Calculate how many windows will be open in the Finder after the search window opens.
			set n to (count windows) + 1
			-- Call up a new search window and wait for it to open.
			keystroke "f" using command down
			repeat until ((count windows) is n)
				delay 0.2
			end repeat
			-- "Click" the pop-up button currently labelled "Kind" and select "Name" from the pop-up menu.
			-- The group containing the pop-up is assumed to be the same for everyone using Tiger.
			tell pop up button 2 of group 3 of group 1 of group 2 of group 1 of splitter group 1 of searchWindow
				perform action "AXPress"
				perform action "AXPress" of menu item 7 of menu 1
			end tell
			-- The search window's name now changes to "Searching <wherever>" and the group's structure changes to include a text field.
			tell group 3 of group 1 of group 2 of group 1 of splitter group 1 of searchWindow
				repeat until (text field 1 exists)
					delay 0.2
				end repeat
				-- Nothing I've tried so far will select the new text field, but its value can be set.
				set value of text field 1 to searchText
			end tell
		end tell
	end tell
end findByName

findByName()

PS. Shutting down completely and starting up again cured the “screwed-up search” problem I mentioned above. :slight_smile:

Second edit: The script now uses perform action “AXPress” instead of click, which seems as if it could be more direct. (But I don’t know for sure.) Window references are now to a specific window rather than simply to the ‘front’ one, which saves having to faff around opening and closing floating windows. Floating windows are now identified by subrole, which, unlike description, doesn’t change with the user’s language.

OMM, running this from Script Debugger 4 fails at the first ‘click’ because the Finder’s Find window is not frontmost. I didn’t presume to fix it, however, Nigel.

Hi, Adam.

I think that’s one of the reasons I’m still using Script Editor after all these years, rather than a “scripting environment” like Script Debugger, Smile, or the long-gone Scripter. It simply has very little environment to get in the way. :slight_smile:

But your comment has made me realise that the script won’t work if the Finder’s floating “Inspector” window is open, since that remains the Finder’s frontmost window and prevents the clicks from reaching the search window. I’ve now edited the script in the post above to close the Inspector temporarily (if it’s open) while the clicking takes place. The Inspector-toggling keystroke, option-command-i, only works if there’s an active selection or a focused, non-search Finder window, so script also opens a temporary Finder window to ensure that the keystroke will work. It’s a bit Heath Robinson, but it works for me. :wink:

Still fails and stalls here:

-- The group containing it is assumed here to be the same for everyone using Tiger.
			tell pop up button 2 of group 3 of group 1 of group 2 of group 1 of splitter group 1 of front window
				click
				click menu item 7 of menu 1
			end tell

Clearly my ‘group’ isn’t the same as yours. Maybe it’s because when I updated to 10.4.8 I did a full combo update (which I routinely do every second or third time) and the UI Browser shows a different progression - not that I can get it to work myself either.

Thanks, Adam. It seems from this and from one or two other threads in which I’ve been involved recently that with GUI Scripting, you can’t even assume the GUI structure will be the same across any two copies of the same version of the same software running on similar machines. And yet you can’t write GUI scripts (or any others) without assuming that certain things will be the same for the user as for the writer. :frowning:

Since last night, I’ve been trying to reduce the number of assumptions made in the script. It’s often possible for a script to “feel” its way towards a required UI element by using whose filters, but even these have to be based on a structure that the scripter knows about. The only way to ignore structure altogether is to use entire contents, which returns a flat list of all the UI elements in the hierarchy of a particular element. For the current purpose “ looking for the only pop-up button in the hierarchy with a particular value “ the script just has to iterate through the list until it finds it. But this is quite slow. Working with the the entire contents of the front window, it takes just over 2 seconds on my 2GHz DP G5 to locate the pop-up button, change its setting, and enter the search text into the text field. (The script I posted last night, hardwired for a particular window structure, takes about 0.4 seconds to do that bit.) But by making a few “ ah “ reasonable assumptions, it’s possible to reduce that to just under a second “ though it’ll still probably look quite clumsy on a slower machine.

  1. It seems reasonable to assume that the buttons will be somewhere within the subhierarchy of group 1 of splitter group 1 of the front window. This produces an entire contents list that’s less than half the length of the one for the entire window. Otherwise the buttons are bound to come somewhere under the splitter group…
  2. It doesn’t actually matter if the “Kind” pop-up’s used or the “Last Opened” one, since they’re identical apart from their initial values and the effect of using either is the same. The script below uses the first one that turns up in the list.
  3. It’s assumed that the initial values of the pop-ups are actually “Kind” and “Last Opened”, or their equivalents in another language. The names in the script can be changed, if necessary, via the variables at the top.
  4. It’s virtually certain that the text field produced will be in the same group as the pop-up button used to produce it.
-- Intended for Tiger only.
-- Uses GUI Scripting.

on findByName()
	-- Localise these terms to your computer's display language.
	set kindInMyLanguage to "Kind" as Unicode text
	set lastOpenedInMyLanguage to "Last Opened" as Unicode text
	set nameInMyLanguage to "Name" as Unicode text
	
	set targetPopups to {kindInMyLanguage, lastOpenedInMyLanguage}
	set searchText to text returned of (display dialog "Search for disk items whose names contain." default answer "")
	
	tell application "System Events"
		tell application process "Finder"
			set frontmost to true
			-- If the View Options floating window is open, it'll take on the same name as the search window,
			-- but be higher up the pecking order. The search window itself can be referenced by index, but the
			-- references returned as its 'entire contents' refer to it by name. When the script tries to access
			-- these items, the references are followed through the first window with that name, which will be
			-- the View Options window if that's open, not the window they're actually in. This will cause the
			-- script to error. The View Options window _must_ therefore be temporarily closed here if it's open.
			-- There's no such problem with the floating Inspector window, which can be left open.
			set viewOptionsOpen to false
			set floatingWindows to windows whose subrole is "AXFloatingWindow"
			repeat with thisFloater in floatingWindows
				-- The View Options window only has one button (its Close button) at root level.
				if ((count thisFloater's buttons) is 1) then
					set viewOptionsOpen to true
					-- Close the View Options window.
					keystroke "j" using command down
					repeat while (thisFloater exists)
						delay 0.2
					end repeat
				end if
			end repeat
			
			-- The "New Search" window will be the frontmost one _behind_ any floating windows.
			set searchWindow to a reference to window ((count (windows whose subrole is "AXFloatingWindow")) + 1)
			-- Calculate how many windows will be open in the Finder after the search window opens.
			set n to (count windows) + 1
			-- Call up a new search window and wait for it to open.
			keystroke "f" using command down
			repeat until ((count windows) is n)
				delay 0.2
			end repeat
			set originalName to searchWindow's name
			
			-- Initiate a script object to speed up the list searches below.
			script o
				property l : missing value
			end script
			
			-- Identify the pop-up button currently labelled "Kind" “ or "Last Opened" if that turns up first “
			-- "click" it (ie. perform the click-response action), and select "Name" from the pop-up menu.
			set o's l to (get entire contents of group 1 of splitter group 1 of searchWindow)
			repeat with i from 1 to (count result)
				set thisElement to item i of o's l
				if (thisElement's class is pop up button) and (thisElement's value is in targetPopups) then
					perform action "AXPress" of thisElement -- Open the pop-up menu.
					perform action "AXPress" of menu item nameInMyLanguage of menu 1 of thisElement -- Select "Name".
					exit repeat
				end if
			end repeat
			
			-- The search window's name now changes to "Searching <wherever>" and the group's structure changes to include a text field.
			repeat while (searchWindow's name is originalName)
				delay 0.2
			end repeat
			
			-- Identify the group containing the pop-up button now called "Name" and enter the search text into its text field.
			set o's l to (get entire contents of group 1 of splitter group 1 of searchWindow)
			repeat with i from 1 to (count result)
				set thisElement to item i of o's l
				if (thisElement's class is group) and (value of thisElement's pop up buttons contains nameInMyLanguage) then
					set value of text field 1 of thisElement to searchText
					exit repeat
				end if
			end repeat
			
			-- Reopen the View Options window if it was open before.
			if (viewOptionsOpen) then keystroke "j" using command down
		end tell
	end tell
end findByName

findByName()

Later edit: This script has now been edited to incorporate the same improvements as the version in post #1 above, which means that it doesn’t have to close the floating Inspector window. But account is also taken of the fact that the View Options window is a floating window too, which was overlooked before. Since this script accesses items returned by entire contents, the View Options window has to be closed temporarily if it’s open, for reasons explained at length in the long comment near the top.

Sorry I didn’t discover this sooner, Mr. G. Code Exchange is not on my screen unless I scroll down to see that it has unread threads.

To cut to the chase: It works now. I find for some reason that it’s substantially more reliable if I close the Find window before commencing a new search, but it will successfully find parts of names without any further fiddling. :smiley: Nor is is ‘slow’ - on my dcG5/2.3 typing in the search string and waiting for the Finder’s find takes longer and the menu seems to flash down as soon as the window is open.

No problem, Mr B. You appear to have replied only 32 minutes or so after I posted the revised script. The twelve-hour clock used on this site can be a little confusing. Like you, I don’t see Code Exchange on the BBS front page either unless I scroll down to look. It’s loads of adverts with only the Mac OS and OS X links peering over the bottom of the screen. :wink:

I didn’t imagine it would seem particularly slow on your machine, Mr B! :slight_smile: I can’t explain your reliability issue, although I’d guess it was something to do with timing. GUI Scripts only push the buttons; they don’t hang around for the application to tell them it’s carried out the associated task. Maybe your computer’s simply too fast! :lol:

Hi, Nigel;

I’ve determinined that the unreliability only occurs if I have no Finder windows open at all - i.e., searching the entire disk (which on mm is fast enough that I don’t have to be specific). I mostly use this tool to search for scripts, but don’t bother to go to the script folder to do it. This tool is great for that and I’ve given it a hot key in FastScripts.

It still bothers me that I don’t know why the original version of the script in post #1 didn’t work for Adam, who has the same Finder version as me.

Further thought and research over the weekend have turned up the fact that clicks can be directed “ in this case, at least “ at elements in any particular window, not just the front one. This greatly improves both scripts. I’ve also switched from click-ing items to perform-ing their actions, which might be more direct. (But I don’t know if it is.)

Both scripts are re-edited above. I still prefer the one in post #1, which is faster, language independent, and doesn’t require any floating windows to be closed. But if it doesn’t work at all for other people, the slower, language-dependent, and (if the View Options window’s open) slightly clunky one in post #5 might serve the turn.