I’ve had a look at a few articles to try and find something that will help me with this but I’m not 100% sure if it’s what I need.
Basically what I’m trying to do is put together a script that will toggle a folder view in a list.
So let’s say I highlighted a folder, in a list of folders, in finder, I’d then run the script and it would effectively click on the little triangle at the side of the folder name. This would then show the contents. It would also toggle the same setting for certain folders that exist within that folder and whose names don’t change.
I’m not sure if I’m heading in the right direction with ‘container’ and ‘expandable’?
See the Finder’s Dictionary. What you are trying to change is called the “current view”, a property of a Finder Window. It’s constants are: ‘column view’, ‘group view’, ‘icon view’ and ‘list view’. You can find out which is showing by asking:
tell application "Finder" to set i to current view of window 1
which requires that a Finder window actually be showing, or that you bring it to the front first.
To set them, I’d use GUI scripting in the Finder’s “View” menu, but can’t help you with code for that - I’m hopeless at GUI scripting.
I think it’s not quite what I’m after. I already have the folder in ‘list’ view.
Under that I have a list of folders. What I’m trying to do is effectively click on the little triangle at the side of the folder name to reveal a list of the items contained within.
tell application "Finder"
activate
tell front Finder window
if not (exists) or (count containers) is 0 then return beep (* or invoke some kind of dialog/error *)
set l to current view is not list view
select (* in case some other type of window is frontmost *)
end tell
end tell
tell application "System Events" to tell window 1 of application process "Finder"
set t to it
tell splitter group 1 to if exists then set t to it
if l then key code 19 using command down
key code 0 using command down
key code 124 - (value of UI element 1 of group 1 of (first row of outline 1 of t's ¬
scroll area -1 where value of UI element 1 of group 1 > -1)) using option down
end tell
tell application "Finder"
reveal front Finder window's item 1 (* forces a scroll-up after contracting a long list *)
select {} (* deselect *)
end tell
Having done some further research I’ve managed to get the code below doing what I want:-
tell application "System Events"
tell process "Finder"
click UI element 1 of group 1 of row 12 of outline 1 of scroll area 2 of splitter group 1 of window "pdf downloads"
end tell
end tell
This code toggles the triangle and reveals a list of what’s contained in the relevant folder. On running the script again it unreveals the list.
Now I’m trying to get the result of the code below into the code above:-
tell application "Finder"
set x to selection
end tell
I think the value of AXRow is what I need. The ‘row’ value in the top code corresponds with the position of the folder in the list i.e. position 12. I’ve tried setting up a few folders and changing this value and it seems to work.
Any help of how I can get the ‘row’ value of the selected item would be appreciated.
I downloaded the kai’s script and it doesn’ work on a french keyboard.
May you explain what are the used key code supposed to do?
keystroke works on every keyboard (at least occidental ones) while key codes are dedicated to some ones.
The one used here are OK for an american keyboard, not for a french one.
Hi Adam,
Thanks again for the posting of Kai’s code it’s been a big help.
I’m still trying to get the current row position of a selected folder in a list of folders. That will then allow me to toggle the view of just that folder.
Kai’s solution toggles multiple folders which in some circumstances will be useful, however the folder I’m working with has hundreds of folders in it and I don’t want to toggle the view for all of them.
I have no luck with the kai’s script on my french system.
I tried to replace the “non-working” key code 19 . instruction by
keystroke “2” using {command down, option down, shift down} – what I must type by hand
without success.
So I tried to trigger directly the menu item by
click menu item 2 of menu 5 of menu bar 1
no success.
At last I move the instruction in the first tell block like that:
tell application “Finder”
activate
tell front Finder window
if not (exists) or (count containers) is 0 then return beep (* or invoke some kind of dialog/error )
set l to current view is not list view
select ( in case some other type of window is frontmost *)
if l then tell application “System Events” to tell application process “Finder” to click menu item 2 of menu 5 of menu bar 1
end tell
end tell
tell application “System Events” to tell application process “Finder” to tell window 1
set t to it
tell splitter group 1 to if exists then set t to it
log t
key code 0 using command down
key code 124 - (value of UI element 1 of group 1 of (first row of outline 1 of t’s ¬
scroll area -1 where value of UI element 1 of group 1 > -1)) using option down
end tell
tell application “Finder”
reveal front Finder window’s item 1 (* forces a scroll-up after contracting a long list )
select {} ( deselect *)
end tell
This time, the window really switches in columns mode but the trailing code doesn’t.
Analysis: the GUI Scripting part of kai’s script selects all the items in the window, identifies the current state of the disclosure triangle of the first folder in the list, and performs keycode 124 (right arrow) with option down if the state value’s 0. This discloses the entire contents of the folder and of any others that are selected. If the disclosure triangle value’s 1, the script performs keycode 123 (left arrow) with option down to undisclose (for want of a better word!) the entire contents of all selected folders. This version is adapted from it to demonstrate how it could work with just one selected folder. It’s not meant to be a complete script in itself as I’m not entirely sure how Nick wants it to work.
tell application "Finder"
activate
tell front Finder window
if not (exists) or ((count containers) is 0) or (current view is not list view) then return beep (* or invoke some kind of dialog/error *)
end tell
set theFolder to item 1 of (get selection)
if (theFolder's class is not folder) then return beep
set selection to theFolder -- Make sure only one item is selected.
set folderName to theFolder's name
end tell
tell application "System Events" to tell window 1 of application process "Finder"
set t to it
tell splitter group 1 to if exists then set t to it
key code 124 - (value of UI element 1 of group 1 of (row 1 of outline 1 of t's ¬
scroll area -1 where name of UI elements of group 1 contains folderName)) using option down
end tell
OK. Here’s a multiple-folder version. Select the folders whose disclosure states you want toggled and run the script. It works if you select subfolders in disclosed hierarchies too. I’m not happy about the workround to get full hierarchy disclosure after a restart, but maybe someone can think of a better way to do it:
-- Adapted from a script by kai.
on main()
-- Check the front Finder window for existence, folders, and list view. Focus on it. Get the selection.
tell application "Finder"
activate
tell front Finder window
if not (it exists) or ((count containers) is 0) or (current view is not list view) then return beep (* or invoke some kind of dialog/error *)
set windowTarget to its target
select -- Ensure the focus is on this window.
end tell
set theSelection to selection -- The selection previously made in this window by the user.
end tell
-- Test the window's GUI structure for the container of the elements we need to find.
tell application "System Events"
tell window 1 of application process "Finder"
set t to it
tell splitter group 1
if (it exists) then set t to it
end tell
end tell
end tell
-- Sort the selected items into those that have to be opened and those that have to be closed.
set {toOpen, toClose} to {{}, {}}
repeat with i from 1 to (count theSelection)
tell application "Finder"
set thisItem to item i of theSelection
set isFolder to (thisItem's class is folder)
end tell
if (isFolder) then
-- If this item's a folder, get its name.
tell application "Finder" to set folderName to thisItem's name
-- Get the current disclosure triangle status for the list-view line containing that name.
-- 0 = triangle pointing right (folder contents hidden); 1 = triangle pointing down (folder contents revealed).
tell application "System Events" to set triangleState to (value of UI element 1 of group 1 of (row 1 of outline 1 of t's ¬
scroll area -1 where name of UI elements of group 1 contains folderName))
-- Before sorting this item, check that it won't be hidden by the closure of a folder further up the hierarchy.
-- If it will be, there's no point in including it, since the system will ignore it and it complicates the reselection process below.
tell application "Finder"
set wontBeHidden to (thisItem's container is windowTarget)
if not (wontBeHidden) then
-- This is a subfolder in a revealed hierarchy. Check the folders further up the hierarchy.
-- Folders come before their subfolders in the 'entire contents' list, so any
-- up-hierarchy ones that are to be closed in this run have already been identified.
set theContainer to thisItem's container
repeat until ({theContainer} is in toClose) or (theContainer is windowTarget)
set theContainer to theContainer's container
end repeat
if (theContainer is windowTarget) then set wontBeHidden to true
end if
-- If this folder won't be hidden, add it to the appropriate list for opening or closing.
if (wontBeHidden) then
if (triangleState is 0) then
set end of toOpen to thisItem
else
set end of toClose to thisItem
end if
end if
end tell
end if
end repeat
-- Bulk-toggle the folders to be closed, then those to be opened.
toggle(toClose, 123) -- 123 is the key code for left arrow.
toggle(toOpen, 124) -- 124 is the key code or right arrow.
-- Display the window contents from the top and reselect the toggled folders.
tell application "Finder"
reveal item 1 of windowTarget
set selection to toOpen & toClose -- 'select' would show any subfolders in a new window.
end tell
end main
(* Bulk-perform all the toggling in a given direction. (Open or close). *)
on toggle(folderList, keyCode)
if ((count folderList) > 0) then
tell application "Finder" to set selection to folderList
tell application "System Events"
if (keyCode is 124) then
-- After a restart, option-right-arrow doesn't reveal entire hierarchies immediately,
-- but adds a layer at a time to each hierarchy as it's used successively on the
-- hierarchy's top folder. Once the lowest level's reached, the entire hierarchy's
-- revealed every time - except that the system remembers which subfolders
-- have been opened or closed differently from the rest. To allow for post-restart
-- situations, this handler does six option-right-arrows when revealing hierarchies.
-- Increase the number if necessary.
repeat 5 times
key code keyCode using option down
delay 0.2
end repeat
end if
key code keyCode using option down
end tell
end if
end toggle
main()
Thanks to Nigel Garvey comments I was able to adjust the kai’s script so that it works on a french keyboard.
I assumes that as is, it works also on US ones.
tell application "Finder"
activate
tell front Finder window
if not (exists) or (count containers) is 0 then return beep (* or invoke some kind of dialog/error *)
set l to current view is not list view
select (* in case some other type of window is frontmost *)
end tell
end tell
tell application "System Events" to tell application process "Finder"
if l then click menu item 2 of menu 5 of menu bar 1 (* View > as list *)
tell window 1
set t to it
tell splitter group 1 to if exists then set t to it
keystroke "a" using {command down} (* Select All *)
key code 124 - (value of UI element 1 of group 1 of (first row of outline 1 of t's ¬
scroll area -1 where value of UI element 1 of group 1 > -1)) using option down
(* send left or right arrow *)
end tell
end tell
tell application "Finder"
reveal front Finder window's item 1 (* forces a scroll-up after contracting a long list *)
select {} (* deselect *)
end tell
set right_arrow to ASCII character 29
tell application “Finder” to activate
tell application “System Events”
tell process “Finder”
keystroke right_arrow using command down
end tell
end tell
Edited: btw, you can fully expand with the Option key:
set right_arrow to ASCII character 29
tell application “Finder” to activate
tell application “System Events”
tell process “Finder”
keystroke right_arrow using {option down, command down}
end tell
end tell
To collapse the outline, use the left arrow (ascii character 28).
I don’t know why kai used key codes rather than keystrokes here, but I’m sure he must have had a good reason. He also seems deliberately to have avoided scripting the Finder itself to set current view of front window to list view.
I don’t personally know of any documentation regarding key codes, but there’s a useful little freeware application called Full Key Codes that displays them, if you’re interested.
Thanks for your help with my query and for taking the time to write something.
Your solution worked great thanks.
Having played around with what you’d written I then looked at the keycode thing and thought about something really simple and came up with this:-
tell application "Finder"
activate
select window "NAME OF WINDOW"
end tell
tell application "System Events"
tell process "Finder"
key code 124
key code 125
key code 125
key code 125
key code 125
key code 125
key code 125
key code 124
end tell
end tell
(*
123 - left arrow
124 - right arrow
125 - down arrow
126 - up arrow
*)
All you have to do is highlight the folder you want to toggle and run the script. This version opens the folders, you’d obviously need to do something that does the reverse.
Because the folder structure is the same in every case this solution works however I have had one or two anomolies. I think they can be ironed with a little checking. It’s a little bit of a dirty way of doing it but it seems to work and do exactly what I want.
-1- I was so much involved with the key code versus keystroke problem that I forgot the easy road to switch the window mode ;-(
-2- Of course, I quickly downloaded the app.
So I now know that
key code 0 is “a” on US keyboard but is “q” on french ones.
So I insist to ask for scripters to use keystroke which is stable in lieu of key code which is not.
I met only once a problem with keystroke. For more than one year, on french keyboards, Mac OS X was sending a “q” when we asked it to keystroke “i” (and of course a “Q” when keystroking “I”).