RSS LinkedIn Twitter

Processing Drag-n-Drop Files/Directories Recursively in Adobe AIR

March 10th, 2011 Categories: AIR, File I/O, Flex 3, Flex 4

I love being able to drag-and-drop files or directories onto my AIR apps and have it recursively process all of the files in the directory structure. This is handy for batch file processing utilities, which seems to be a common theme in many of my AIR apps.

The first thing you need to do is set up your AIR app to handle the drag and drop operation. This is pretty straightforward, and is done by setting up listeners for the NATIVE_DRAG_ENTER and NATIVE_DRAGE_DROP events.

private function onCreationComplete() : void {
	this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, onDragIn);
	this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, onDrop);
}

The code that handles the NATIVE_DRAG_ENTER event needs to determine whether or not to accept the dragged items. In this method you see it essentially accepting anything that is dragged into the app. This does not have to be the case, if you prefer to be more selective about the files that are dragged in.

There are several method the more discriminating users may want to call on the event. The event has a clipboard object, with a number of methods. getFormat(), and getData() are the two most useful in my opinion. You can use these to check for a particular filename or extension, etc.

private function onDragIn(event : NativeDragEvent) : void {
	NativeDragManager.acceptDragDrop(this);
}

You see I use the clipboard.getData() method to retrieve the list of dropped files. If you’re only interested in drag-and-drop, you can stop here. The method processDroppedFiles, which accepts an array, is the method that starts the actual processing.

private function onDrop(event : NativeDragEvent) : void {
	try {
		var dropfiles:Array = event.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
		processDroppedFiles(dropfiles);
	}
	catch (error : IOError) {
		trace("Error during drag-and-drop procedure.");
	}
}

A file in my files array can either be a file, in which case I want to do my processing. That’s what the method processFile() does, which I will not detail in this post, because it does whatever work your application is doing with the files.

The file could also be a directory, in which case, I want to call processDirectory(). isDirectory is a property on the file that is true if the file is a directory, and false if… well, duh.

private function processDroppedFiles(files : Array) : void {
	for each (var file:File in files){
		if (file.isDirectory)
			processDirectory(file);
		else
			processFile(file);
	}
}

I could have skipped out on this method if I wanted to… I’m adding it to make it a little more clear what’s happening. The method processDroppedFiles() needs an Array of Files, whereas processDirectory() accepts a File. At this point, we know that the file in question is a directory, so we call the getDirectoryListing() method which returns an Array, and we recurse to processDroppedFiles().

private function processDirectory(dir : File) : void {
	processDroppedFiles(dir.getDirectoryListing());
}

As I pointed out, you could just as easily have included the recursive call in the processDroppedFiles() method itself, like this:

private function processDroppedFiles(files : Array) : void {
	for each (var file:File in files){
		if (file.isDirectory)
			processDroppedFiles(file.getDirectoryListing());
		else
			processFile(file);
	}
}

And this will traverse the directory tree, eventually calling processFile() on each file in the tree.

Tags:

3 Responses to “Processing Drag-n-Drop Files/Directories Recursively in Adobe AIR”

  1. pb_
    November 23rd, 2011 at 16:17
    1

    Greetings from your fellow brothers to the North (Morgan Utah)

    Hey – couldn’t get this to work. It’s like the event listeners are not kicking off. What am I missing?

    Here is my code (no guarantee that the blog won’t strip out the ML). Any ideas?

    [code]
    <?xml version="1.0" encoding="utf-8"?>
    <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009&quot;
    xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    creationComplete="onCreationComplete()"
    >
    <fx:Declarations>
    <!– Place non-visual elements (e.g., services, value objects) here –>
    </fx:Declarations>

    <fx:Script>
    <![CDATA[
    private function onCreationComplete() : void {
    this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, onDragIn);
    this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, onDrop);
    }

    private function onDragIn(event : NativeDragEvent) : void {
    NativeDragManager.acceptDragDrop(this);
    }

    private function onDrop(event : NativeDragEvent) : void {
    try {
    var dropfiles:Array = event.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
    processDroppedFiles(dropfiles);
    }
    catch (error : IOError) {
    trace("Error during drag-and-drop procedure.");
    }
    }

    private function processDroppedFiles(files : Array) : void {
    for each (var file:File in files){
    if (file.isDirectory)
    processDirectory(file);
    else
    processFile(file);
    }
    }

    private function processDirectory(dir : File) : void {
    processDroppedFiles(dir.getDirectoryListing());
    }

    private function processFile(file:File): void {
    trace(file);
    }
    ]]>
    </fx:Script>
    </s:WindowedApplication>

    [/code]

    • November 23rd, 2011 at 16:28
      2

      That’s strange. I just copied your code verbatim into a new AIR project and it works perfectly. I tested it using SDK 4.1 and 4.5.1. Which version of the SDK are you using?

  2. pb_
    November 23rd, 2011 at 17:23
    3

    Hey I figured it out. Our machines are locked down tight. If you don’t run your AIR app as Admin, then the drag/drop events are not sent for some reason. Running it as as Admin fixed the issue!

Leave a Comment

*