I’m looking through all the example code I can and I’m very much stuck on something I assume should be simple. I’m also very new to all this.
I I’m trying to write a applescript app with the xcode toolset which has a table that will accept a drag/drop set of files, and then recursively go through the list adding the file names to the list.
The example code apple provides shows how to get the name of a bunch of files dropped in but it will not recurse through the list and add just the names of files. It seems that when I use the “drag info dragInfo” syntax I don’t actually get the files but just the POSIX form of the name. Therefore I can’t test the items to determine if they are a folder and should be opened and listed as well.
I’m trying to get something like this… (which of course does not work)
drop theObject --drag info dragInfo
set theFiles to {}
set preferred type of pasteboard of dragInfo to "file"
set theFiles to the contents of dragInfo
repeat with theItem in theFiles
recursively_add_item_to_list(theItem)
end repeat
set preferred type of pasteboard of dragInfo to ""
return true
end drop
That’s a clever solution. I was thinking more along the lines of getting a list of the actual items as is done in a non-studio script in the “on open” handler.
When I try this approach I’m getting this error, which I don’t know how to interpret.
Can't make «class psxf» (item 1 of {"/my/testFolder"}) of application "System Events" into type alias. (-1700)
I almost have this working but I’m looking for a bit more help.
I seem to be having a problem with recursion in applescript. If I only try and add files it works fine, and it also seems to traverse recursively through folders, however if folders are found it skips over adding the files to the list.
is the variable theFiles not seen as local within the function?
end result, I want a list of all files (not folders) in the entire directory tree. (Assumption is made that there are no duplicate file names.)
on awake from nib theObject
set theDataSource to make new data source at end of data sources with properties {name:"files"}
make new data column at end of data columns of theDataSource with properties {name:"files"}
set data source of theObject to theDataSource
tell theObject to register drag types {"file names"}
end awake from nib
on add_item_to_list(theItemName, theDataSource)
tell application "System Events"
set the theItem to get (POSIX file (theItemName as string)) as alias
if kind of (theItem) is "Folder" then
set is_a_file to false
set current_path to theItemName
set theFiles to list folder theItem without invisibles
repeat with theItem in theFiles
set theItem to current_path & "/" & theItem
set the theItem to get (POSIX file (theItem as string)) as alias
if kind of (theItem) is "Folder" then
set newName to POSIX path of theItem
tell me to add_item_to_list(newName, theDataSource)
end if
end repeat
else
(* This won't work for some reason: the "set contents data cell" line
will not compile if it is within the tell application 'System Events' block"
--set theDataRow to make new data row at end of data rows of theDataSource
--set contents of data cell "files" of theDataRow to theItem
*)
set is_a_file to true -- so I have to resort to this silliness
end if
end tell
if is_a_file is true then
set theDataRow to make new data row at end of data rows of theDataSource
set contents of data cell "files" of theDataRow to theItem
end if
end add_item_to_list
on drop theObject drag info dragInfo
set theFiles to {}
set preferred type of pasteboard of dragInfo to "file names"
try
set theFiles to the contents of pasteboard of dragInfo
on error
display dialog "Could not set the list of files for some reason."
end try
if (count of theFiles) > 0 then
set theDataSource to data source of theObject
set update views of theDataSource to false
delete every data row of theDataSource
repeat with theItem in theFiles
add_item_to_list(theItem, theDataSource)
end repeat
set update views of theDataSource to true
end if
set preferred type of pasteboard of dragInfo to ""
return true
end drop
I would love it if someone who is actually good at this could show me the light and a better way to accomplish this.
on awake from nib theObject
-- Create the data source for the table view
set theDataSource to make new data source at end of data sources with properties {name:"files"}
-- Create the "files" data column
make new data column at end of data columns of theDataSource with properties {name:"files"}
-- Assign the data source to the table view
set data source of theObject to theDataSource
tell theObject to register drag types {"file names"}
end awake from nib
(* Used to add items to the list *)
on add_item_to_list(theItem_path, theDataSource)
set theItem_test to do shell script "/bin/ls -l " & theItem_path
set theItem to get (POSIX file (theItem_path as string)) as alias
set theItem_test to (words of theItem_test)
if (count of theItem_test) > 0 and the first item of theItem_test is "total" then
set is_a_file to false
set current_path to theItem_path
set theFiles to list folder theItem without invisibles
repeat with theItem in theFiles
set theItem_path to current_path & "/" & theItem
set theItem_test to do shell script "/bin/ls -l " & theItem_path
set theItem_test to (words of theItem_test)
if (count of theItem_test) > 0 and the first item of theItem_test is "total" then
add_item_to_list(theItem_path, theDataSource)
else
if (count of theItem_test) > 0 then
set theDataRow to make new data row at end of data rows of theDataSource
set contents of data cell "files" of theDataRow to theItem
end if
end if
end repeat
else
if (count of theItem_test) > 0 then
set theDataRow to make new data row at end of data rows of theDataSource
set contents of data cell "files" of theDataRow to theItem
end if
end if
end add_item_to_list
on drop theObject drag info dragInfo
-- Get the list of data types on the pasteboard
set dataTypes to types of pasteboard of dragInfo
set theFiles to {}
set preferred type of pasteboard of dragInfo to "file names"
try
set theFiles to the contents of pasteboard of dragInfo
on error
display dialog "Could not set the list of files for some reason."
end try
-- Make sure we have at least one item
if (count of theFiles) > 0 then
--- Get the data source from the table view
set theDataSource to data source of theObject
-- Turn off the updating of the views
set update views of theDataSource to false
-- Delete all of the data rows in the data source
delete every data row of theDataSource
-- For every item in the list, make a new data row and set it's contents
repeat with theItem in theFiles
add_item_to_list(theItem, theDataSource)
end repeat
-- Turn back on the updating of the views
set update views of theDataSource to true
end if
-- Set the preferred type back to the default
set preferred type of pasteboard of dragInfo to ""
return true
end drop
Don’t know if that’s what you’re exacly after - but maybe it helps?
Here an attempt for a routine to build a list of full paths of all files (not folders) in a folder and all it’s subfolders and subsubfolders … (without using recursion):
Edit: this script contains a bug - please read two messages below …
set thePath to (POSIX path of (choose folder))
set allFiles to do shell script "cd " & thePath & "; ls -l -R | grep -v -e\"^d\" | grep -v -e\"^total\" | grep \" \""
set fullPath to thePath
set fileList to {}
repeat with theLine in paragraphs of allFiles
if character 1 of theLine = "." then
set folderPath to ((characters 3 thru -2 of theLine) as string) & "/"
set fullPath to thePath & folderPath
else
set fileList to fileList & (fullPath & (do shell script "echo " & quoted form of theLine & "| awk 'n=8 {while ($(n++) != \"\") printf$n\" \"}' | perl -pe 's/ *$//'"))
end if
end repeat
get fileList
after sleeping a night over this problem I found two cases where my above script fails:
when the user name contains spaces (then there will be more columns than 8 to delete)
when the file names contain double or triple etc. spaces.
Sorry, I guess this attempt was useless
But here is a new one which seems to work - and it is even shorter and faster:
set thePath to (POSIX path of (choose folder))
set allFiles to (do shell script "cd " & quoted form of thePath & ";find * -ls | grep -v -e\"^............ d\" | grep -v -e\"/\\.\"")
set fileList to {}
repeat with theLine in paragraphs of allFiles
set fileList to fileList & (thePath & ((characters 70 thru -1 of (theLine as string)) as string))
end repeat
get fileList