applescripting finder windows

beginner scripter here… i have been trying to create an applescript that would automatically set the window size and position of folders and subfolders based on their hierarchy.

i found an applescript by Pier Kuipers called “stack finder windows” and modified it to suit my needs. the script sets a default window size and variable window size based on the number of items in the folder. the window position is also offset based on the hierarchy. the script works perfectly, as long as the folders are located on the startup volume. i think Pier designed the script to work on any volume and since i don’t know the mechanics of how this script works, i have had difficulty troubleshooting it. on volumes other than the startup, the script seems to process some folders ok, but then somehow inserts the startup volume into the path name and can no longer find the remaining folders to process.

if anyone has any suggestions or can help troubleshoot this script it would be greatly appreciated. also, since my request is probably over the top - i would like to add one more thing, how do i modify the script to run when a folder is dropped on it rather than through a dialog box?

thanx, mike ellison

here is a copy of the script:

property x : 0
property y : 0
global position1
global position2
global size1
global size2
global sizeVariable
global numFolders
global numItems
copy 13 to position1
copy 47 to position2
copy 404 to size1
copy 216 to size2
with timeout of 3000 seconds
	tell application "Finder"
		activate
		set theFolder to {choose folder with prompt "Select a Folder or a Disk:"} as text
		select item theFolder
		open selection
		set x to 13
		set y to 47
	end tell
	processFoldersOf(theFolder)
	tell application "Finder"
		set selection to {item theFolder}
		open selection
		-- determine window size based on items
		set numItems to (count item of the front window)
		-- determine size of window
		if numItems * 7 then
			-- minimum size
			set size2variable to {size2}
		else
			if numItems * 24 then
				-- maximum size
				set size2variable to ((24 * 18) + 72)
			else
				set size2variable to ((numItems * 18) + 72)
			end if
		end if
		-- set the size
		tell front window
			set position to {position1, position2}
			set size to {size1, size2variable}
			close
		end tell
	end tell
end timeout
on processFoldersOf(theFolder)
	tell application "Finder"
		-- determine number of folders to process
		set numFolders to (count every folder of window of item theFolder)
	end tell
	repeat with i from 1 to numFolders
		tell application "Finder"
			set selection to {folder i of front window}
			set theSubfolder to (open selection) as text
			set x to (x + 28)
			set y to (y + 21)
			-- determine window size based on items
			set numItems to (count every item of front window)
			if numItems * 7 then
				-- minimum size
				set size2variable to {size2}
			else
				if numItems * 24 then
					-- maximum size
					set size2variable to ((24 * 18) + 72)
				else
					set size2variable to ((numItems * 18) + 72)
				end if
			end if
		end tell
		processFoldersOf(theSubfolder)
		tell application "Finder"
			set selection to item theSubfolder
			tell front window
				set size to {size1, size2variable}
				set position to {x, y}
				close
			end tell
			set x to (x - 28)
			set y to (y - 21)
		end tell
	end repeat
end processFoldersOf

I don’t see an obvious place the startup volume would be inserted.

Wild guess: because the script makes frequent use of “the selection” instead of opening folders or counting their contents directly, any mouse click (or typing in the finder, etc.) by the user while the script is running will change “the selection” target from the the selection made by the script to the the selection made by the user. (Hmm… that is if you intend the script to work on a disk named “Charles” but while the script is running click on the disk named “Betty”, the script will direct all further commands to Betty.)

the actions of this script work on what should be the front window as the script progresses through the hierarchy of folders. this is where the script loses track of where the folders are (when on a non startup volume). full pathnames to each folder would be more reliable, but it seems kinda hard to do with the repeat command.

thanks, mike

I can’t really help much here, because I never use repeat loops with numbers, if the items iterated have names. so instead of the script’s:

set numFolders to count of folder in folder path_to_folder
 repeat with i from 1 to numfolders
  tell application "Finder"
   set selection to {folder i of front window}
   set theSubfolder to (open selection) as text etc...

I use:

tell application "Finder"
	set folder_list to every folder of folder path_to_folder
	repeat with a_folder in folder_list
		set path_name to contents of (a_folder) -- dereference loop variable
		-- do stuff to folder this_folder
	end repeat
end tell

it’s confusing for me to sort through the script’s many uses of “the selection.” The script uses recursion,which is a confusing concept for beginners and part-timers. (I have to test a script several times until I set the halting conditions properly and put the recursive call in the proper place.)I think you’d be better off rewriting from scratch.

macguy

thanks macguy,
i think that you are right about the selection command being the source of the problem.
i replaced the lines of script:

set selection to {item theFolder}
open selection

with:

open item theFolder

and the script worked ok, but i was unable to replace the lines:

set selection to {folder i of front window}
set theSubfolder to (open selection) as text

these lines occur in the repeat section of the script. i had applescript display a dialog with the pathname of the folders it was looking for, as the repeat ran along. and this is where the pathname goes awry. i can’t figure out how to replace these two lines. any suggestions?

thanks, mike

macguy,

i tried using your sample script to duplicate the actions of Piers script. I was able to process folders whose names were contained in the “folder_list” variable, but i was unable to do this with the extended hierarchy of sub folders.

Pier’s script opens the 1st folder of the 1st window and then the 1st folder of the next window and so on until the script finds no more 1st folders to open. Then the script works backwards from the last open folder, and proceeds to work on folder 2, 3 etc, closing windows as it works its way back. This structure allows the script to position the folders across and down based on their hierarchy. Is there a way to do this with your sample script? Is there a way i can have a variable keep track of the path to folders as they are opened by the script?

thanx, mike ellison

i found an applescript by Pier Kuipers I’m not sure what the original script does, as it fails on my computer (with window size error messages in the Finder).
The following is built for a 1024x768 pixel screen, but it will work on any size with these limits: maximum number of folders tiled left to right at an offset of 24 pixels: 30 or so; maximum number tiles top to bottom at an offset of 24 pixels: 20 or so. This should be reasonable number.

property dimension : 210 -- pixels wide & pixels tall
property H_original : 16 -- horizontal coordinate of upper left corner of first window
property V_original : 64 -- vertical coordinate of upper left corner of first window
property title_height : 24 -- height of a window's title bar

on open item_list -- drag 'n' drop
  repeat with one_item in item_list
    tell application "Finder"
      set folder_list to every folder of (contents of one_item)
      set folder_count to count of folders in (contents of one_item)
    end tell
    open_all_folders(folder_list, 0) -- execute first level of folders
  end repeat
end open

open_all_folders(folder_list, heirarchy_level)
  set folder_count to 0
   repeat with one_folder in folder_list
     copy (contents of one_folder) to this_folder
     set these_bounds to my calculate_bounds(heirarchy_level, folder_count)
    tell application "Finder"
       open this_folder
      set bounds of container window of this_folder to these_bounds
      close container window of this_folder
      set new_folder_list to every folder of this_folder
      set folder_count to folder_count + 1 -- to tile left to right, folders must be counted
    open_all_folders(new_folder_list, heirarchy_level + 1) -- execute next level of folders
  end tell
 end repeat
end open_all_folders

 calculate_bounds(heirarchy_level, folder_count)-- adjust the bounds calculations as necessary
  set upperLeft to (H_original + (title_height * folder_count))
  set upperRight to (V_original + (title_height * heirarchy_level))
  set lowerLeft to (upperLeft + dimension)
  set lowerRight to (upperRight + dimension)
  return {upperLeft, upperRight, lowerLeft, lowerRight}
end calculate_bounds

“i tried using your sample script to duplicate the actionsof Piers script. I was able to process folders whose names were contained in the"folder_list” variable, but i was unable to do this with the extended hierarchy of sub folders."

That’s correct. I did not write the recursive call that would open all sub-folders of a folder. I did show how to address every sub-folder by name instead by “the selection”, which should cause the script to address the proper objects and not become confused. To make the script recursive, the repeat loop which open folders needs to be placed in subroutine or in a script object.

Pseudocode:
tell script open_folders to open (top_level_folder, windowsize)
on open_folders (aFolder, windowsize) open aFolder & set its window size
set folder_list to all folders of this folder
repeat with this_folder in folder_list
set aFolder to contents of this_folder
tell script open_folders to open aFolder at windowsize
end
end

this is the structure of the script you’re using, I think. You’ll also need to pass the window_size parameter to the script object or subroutine so that the windows tile properly. Pier’s script does this or uses globals, I don’t recall). Use it as an example. Where the recursive call is placed will determine how the windows tile.

mg

macguy,
Thanks for the recursion script!
I want to modify some of the parameters of the script beyond changing number values for window bounds. I would like to view the actions of the script in the event log of the editor. I tried your workaround:

on open x
end open

becomes

set x to "Hard Drive:folder:folder" -- whatever the applet expects

but could not get it to work with the script. How do I get the above command to work with your script?
thanks again
the epic folder guy

set item list to {"Drive:Folder:Folder","Drive:Folder:Folder:"}
--
-- you must substitute proper path names to folders
--
repeat with one_item in item_list
tell application "Finder"
set folder_list to every folder of (contents of one_item)
end tell
my open_all_folders(folder_list, 0) -- execute first level of folders
end repeat
(* rest of script, e.g., the subroutine calls *)

BTW, the line with folder_count should have been removed. Artifact of sloppy programming. Sorry. And if you retain the drag ‘n’ drop, you should test if the item dropped is a folder (or disk).
Also, if you’re modifying it, in case something goes wrong, test it on something small, that is a folder with few sub-folders, not your entire hard drive.
Also, I didn’t test the above. Kinda busy today. If it doesn’t work, I apologize in advance and will post a proper working version at your request.
macguy

here is a copy of the more or less finished script, thanks for your help macguy : - )
this script sets folders to list view and then stacks their windows according to their heirarchy and also sets the size of the window based on the number of items in the folder.
the script runs kinda slow on my powermac with sys 8.5. - is there a way to get the finder to set folder attributes faster? also, can applescript control the position of the scrollbar?
the script:

property horizontal_start_position : -15 --actual window position includes horizontal_offset
property vertical_start_position : 26 --actual window position includes vertical_offset
property horizontal_offset : 28
property vertical_offset : 21
property horizontal_size : 404
property vertical_size : 216
property vertical_size_minimum : 216
property line_height : 18
property extra_space_at_bottom : 72

on open item_list
	tell application "Finder"
		set the_folder to first item of item_list
		open the_folder
		set heirarchy_level to 1
		set number_of_items to (count every item of the_folder)
		-- set the list view preferences
		set savedView to view of the_folder
		set view of the_folder to name
		set calculates folder sizes of the_folder to false
		set uses relative dates of the_folder to true
		set shows kind of the_folder to true
		set shows version of the_folder to false
		set icon size of the_folder to small
		-- set the size and position preferences
		set window_position to my calculate_position(heirarchy_level)
		set window_size to my calculate_size(number_of_items)
		set position of container window of the_folder to window_position
		set size of container window of the_folder to window_size
		close container window of the_folder
		repeat with one_item in item_list
			set folder_list to every folder of (contents of one_item)
			set folder_count to count of folders in (contents of one_item)
			set heirarchy_level to (heirarchy_level + 1)
			my open_all_folders(folder_list, heirarchy_level) --execute first level of folders
		end repeat
	end tell
end open

on open_all_folders(folder_list, heirarchy_level)
	repeat with one_folder in folder_list
		tell application "Finder"
			open one_folder
			-- set the list view preferences
			set savedView to view of one_folder
			set view of one_folder to name
			set calculates folder sizes of one_folder to false
			set uses relative dates of one_folder to true
			set shows kind of one_folder to true
			set shows version of one_folder to false
			set icon size of one_folder to small
			-- set the size and position preferences
			set window_position to my calculate_position(heirarchy_level)
			set number_of_items to (count every item of one_folder)
			set window_size to my calculate_size(number_of_items)
			set position of container window of one_folder to window_position
			set size of container window of one_folder to window_size
			close container window of one_folder
			set new_folder_list to every folder of one_folder
			if heirarchy_level = 15 then
				set heirarchy_level to 1
			end if
			my open_all_folders(new_folder_list, heirarchy_level + 1) --execute next level of folders
		end tell
	end repeat
end open_all_folders

to calculate_position(heirarchy_level)
	set horizontal_position to (horizontal_start_position + (horizontal_offset * heirarchy_level))
	set vertical_position to (vertical_start_position + (vertical_offset * heirarchy_level))
	return {horizontal_position, vertical_position}
end calculate_position

to calculate_size(number_of_items)
	if number_of_items * 7 then
		-- minimum vertical size
		set vertical_size to vertical_size_minimum
	else
		if number_of_items * 24 then
			-- maximum vertical size
			set vertical_size to ((24 * line_height) + extra_space_at_bottom)
		else
			set vertical_size to ((number_of_items * line_height) + extra_space_at_bottom)
		end if
	end if
	return {horizontal_size, vertical_size}
end calculate_size

thanks for your help macguy :slight_smile:
here is the more or less finished script-if anyone needs a script to do something like this. the applet sizes windows based on their contents and offsets them by their hierarchy. the script runs a little slow on my powermac, but does nicely on the G3. is there a way to get the finder to process folder windows more efficiently? also, can i script the position of the scroll bar (to the top) and close folder arrows? hmmm?
the script doesn’t test for non-folder items dropped on it; not exacty sure how to do that, so the first thing dropped on it should be a folder.
the script:

property horizontal_start_position : -15 --actual window position includes horizontal_offset
property vertical_start_position : 26 --actual window position includes vertical_offset
property horizontal_offset : 28
property vertical_offset : 21
property horizontal_size : 404
property vertical_size : 216
property vertical_size_minimum : 216
property line_height : 18
property extra_space_at_bottom : 72
on open item_list
	tell application "Finder"
		--set item_list to {choose folder with prompt "Select a Folder or a Disk:"}
		set the_folder to first item of item_list
		open the_folder
		set heirarchy_level to 1
		set number_of_items to (count every item of the_folder)
		-- set the list view preferences
		set savedView to view of the_folder
		set view of the_folder to name
		set calculates folder sizes of the_folder to false
		set uses relative dates of the_folder to true
		set shows kind of the_folder to true
		set shows version of the_folder to false
		set icon size of the_folder to small
		-- set the size and position preferences
		set window_position to my calculate_position(heirarchy_level)
		set window_size to my calculate_size(number_of_items)
		set position of container window of the_folder to window_position
		set size of container window of the_folder to window_size
		close container window of the_folder
		--tell application "Finder"
		repeat with one_item in item_list
			--tell application "Finder"
			set folder_list to every folder of (contents of one_item)
			set folder_count to count of folders in (contents of one_item)
			set heirarchy_level to (heirarchy_level + 1)
			my open_all_folders(folder_list, heirarchy_level) --execute first level of folders
			--beep 2
			--end tell
		end repeat
		--end tell
	end tell
end open
on open_all_folders(folder_list, heirarchy_level)
	repeat with one_folder in folder_list
		tell application "Finder"
			open one_folder
			-- set the list view preferences
			set savedView to view of one_folder
			set view of one_folder to name
			set calculates folder sizes of one_folder to false
			set uses relative dates of one_folder to true
			set shows kind of one_folder to true
			set shows version of one_folder to false
			set icon size of one_folder to small
			-- set the size and position preferences
			set window_position to my calculate_position(heirarchy_level)
			set number_of_items to (count every item of one_folder)
			set window_size to my calculate_size(number_of_items)
			set position of container window of one_folder to window_position
			set size of container window of one_folder to window_size
			close container window of one_folder
			set new_folder_list to every folder of one_folder
			if heirarchy_level = 15 then
				set heirarchy_level to 1
			end if
			my open_all_folders(new_folder_list, heirarchy_level + 1) --execute next level of folders
		end tell
	end repeat
end open_all_folders
to calculate_position(heirarchy_level)
	set horizontal_position to (horizontal_start_position + (horizontal_offset * heirarchy_level))
	set vertical_position to (vertical_start_position + (vertical_offset * heirarchy_level))
	return {horizontal_position, vertical_position}
end calculate_position
to calculate_size(number_of_items)
	if number_of_items * 7 then
		-- minimum vertical size
		set vertical_size to vertical_size_minimum
	else
		if number_of_items * 24 then
			-- maximum vertical size
			set vertical_size to ((24 * line_height) + extra_space_at_bottom)
		else
			set vertical_size to ((number_of_items * line_height) + extra_space_at_bottom)
		end if
	end if
	return {horizontal_size, vertical_size}
end calculate_size