How to get access to the items of a drag and drop

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

Coerce the item path to an alias and ask System Events what it is:

tell application "System Events"
	if kind of (POSIX file theDraggedItem as alias) = "Folder" then
		tell me to doSomething()
	end if
end tell

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

Okay, This works but it ain’t pretty.

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

Hey, that’s pretty sweet. I think I’ll try that. Thanks.

Hi tdog,

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 :frowning:

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

D.

This may be a silly question, but how are you actually getting the table to update with the new data?