« Override classes from included libraries
» Contributing to Flex 3 Cookbook

ActionScript, Events, How to, MXML, PHP, Web Service, xml

How To Build a Download Application in Flex

12.05.08 | 1 Comment

In this article I’ll show the same application I presented at FlexCamp Bucharest Romania 2008 - the video from the conference is available here and although it is in Romanian it might be useful. In the presentation I’m showing the power of Flex: doing complex applications with a few lines of codding.

With this article we are just starting because everything is explained in the powerpoint presentation and by the comments inside the source code found at the end of this article.

The application is simple - only one mxml file - and we will study:

  • Multiple Drag and drop (events)
  • HTTPService
  • FileReference
  • URLRequest

On the server-side:

  • dir.php - browsing (http service) – no parameters needed – returns a simple XML
  • download.php - download (url request) – array with the paths that will be included in archive as parameters – returns an archive (tgz)
  • archive.php - class to create arhives

On the client-side:

  • Tree ⇒ HTTPService ⇒ dir.php ⇒ HTTPService ⇒ Tree
  • Refresh ⇒ HTTPService ⇒ dir.php ⇒ HTTPService ⇒ Tree
  • Download ⇒ List ⇒ URLRequest ⇒ FileReference ⇒ file download

We are using multiple selection and dragging so you can drag more that one item from the list. Also the delete key erases the selected items from the list on the right. You can start over by pressing refresh button.

This is the start of it and you can get into it more and more reading the powerpoints and trying the source codes. All this can be downloaded from the end of this article.

Working example is bellow:


What can be added in the future:

  1. download progress with cancellation possibility
  2. upload functionality
  3. user account functionality

The last two points are more difficult because it involves some work on the server-side but is doable.

I’ve posted also the whole flex source code because it is easier to follow the article and study the code in the same page.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" 
    width="439" creationComplete="init()" height="271">
    <mx:HTTPService id="dir" url="{SERVER_URL}dir.php" resultFormat="e4x" />
    <mx:Tree id="leftTree" x="10" y="10" height="250" width="204" 
        dataProvider="{dir.lastResult}" labelField="@name" showRoot="false" 
        dragEnabled="true" dropEnabled="false" allowMultipleSelection="true" 
        click="showThumb(event)"/>
    <mx:List id="downloadList" x="222" y="10" height="135" width="207" 
        allowMultipleSelection="true" dataProvider="{fileListProvider}" 
        dragEnter="handleDragEnter(event)" dragOver="handleDragOver(event)" 
        dragDrop="handleDragDrop(event)" dragExit="handleDragExit(event)" 
        click="showThumb(event)" keyUp="handleKeyUp(event)"/>
    <mx:Button id="downloadButton" x="347" y="153" label="Download" 
        enabled="false" click="initializeDownload(event)" />
    <mx:Button id="refreshButton" x="347" y="239" label="Refresh" 
        click="refresh(event)"  width="82"/>
    <mx:Canvas id="imageHolder" x="222" y="153" width="117" height="108">
        <mx:Image id="imageThumb" x="0" y="0" width="117" height="108" 
            source="{currentPhotoPath}"/>
    </mx:Canvas>
    <mx:Script>
        <![CDATA[
            import mx.messaging.channels.StreamingAMFChannel;
            /* File downloading application
               Drag and drop between two different controlers: tree and list */
 
            import mx.rpc.events.ResultEvent;
            import mx.collections.ArrayCollection;
            import mx.controls.listClasses.ListBase;
            import mx.core.UIComponent;
            import mx.managers.DragManager;
            import mx.core.DragSource;
            import mx.controls.List;
            import mx.events.DragEvent;
 
            // internet - on flexer
            public const SERVER_URL:String = "http://www.flexer.info/wp-content/uploads/2008/05/";
 
            // bindable variable used for the list
            [Bindable]
            public var fileListProvider:ArrayCollection = new ArrayCollection();
 
            // bindable variable used for thumbnail
            [Bindable]
            public var currentPhotoPath:String = "";
 
            public var fRef:FileReference = new FileReference();
 
            public function init():void
            {
                /* initialization function */
 
                // file reference events - used for debug purposes
                fRef.addEventListener(Event.CANCEL, doEvent);
                fRef.addEventListener(Event.COMPLETE, doEvent);
                fRef.addEventListener(Event.OPEN, doEvent);
                fRef.addEventListener(Event.SELECT, doEvent);
                fRef.addEventListener(HTTPStatusEvent.HTTP_STATUS, doEvent);
                fRef.addEventListener(IOErrorEvent.IO_ERROR, doEvent);
                fRef.addEventListener(ProgressEvent.PROGRESS, doEvent);
                fRef.addEventListener(SecurityErrorEvent.SECURITY_ERROR, doEvent);				
 
                // getting folder content
                dir.send();
            }
            private function handleDragEnter(event:DragEvent):void
            {
                /* this function validates the drop */
 
                if (event.dragInitiator is Tree) {
                    var ds:DragSource = event.dragSource;
                    // check if the format is what we need - treeItems
                    if (!ds.hasFormat("treeItems")) 
                        return;
                    var items:Array = ds.dataForFormat("treeItems") as Array;
                    for (var i:Number=0; i < items.length; i++) {
                        var item:XML = XML(items[i]);
                        // we want only files to be dragable
                        if (item.@type != "file") 
                            return; 
                    }   
 
                    // check for the item to be unique
                    var paths:ArrayCollection = downloadList.dataProvider as ArrayCollection;
                    for (var j:Number=0; j < paths.length; j++)
                    {
                        if (item.@path == paths[j].path.toString()) return;
                    }
                }
 
                // accept the drop
                DragManager.acceptDragDrop(UIComponent(event.currentTarget));
            }
            private function handleDragOver(event:DragEvent):void
            {
                /* this function shows feedback to the user */
 
                // show feedback icon
                DragManager.showFeedback(DragManager.COPY);
            }
 
            private function handleDragDrop(event:DragEvent):void
            {
                /* this function adds new items to the list */
 
                // getting source
                var ds:DragSource = event.dragSource;
                // getting target
                var dropTarget:List = List(event.currentTarget);
                // tempoaray array used to add items to list
                var arr:Array;
 
                // getting the nodes dragged 
                // multiple selection is allowed so we have arrays
                if (ds.hasFormat("items")) {
                    arr = ds.dataForFormat("items") as Array;
                } else if (ds.hasFormat("treeItems")) {
                    arr = ds.dataForFormat("treeItems") as Array;
                }
 
                // adding the dragged nodes to list
                for (var i:Number=0; i < arr.length; i++) {
                    // getting node
                    var node:XML = XML(arr[i]);
                    // creating new list item
                    var item:Object = new Object();
                    // setting item's properties
                    item.label = node.@name;
                    // we set path also which is needed for download
                    item.path = node.@path;
                    // add to data provider
                    fileListProvider.addItem(item);
                }
                // finish drag
                handleDragExit(event);
            }			
 
            private function handleDragExit(event:DragEvent):void
            {
                /* this function finishes the drag and drop */
 
                // we hide the feedback
                var dropTarget:ListBase=ListBase(event.currentTarget);
                dropTarget.hideDropFeedback(event);
                // we check the data provider to enable the download button
                if (dropTarget.dataProvider.length > 0)
                    downloadButton.enabled = true;
            }
 
            private function showThumb(event:MouseEvent):void
            {
                /* this function shows the thumbnail 
                   used for both tree and list click events */
 
                // if click is on the tree
                if (event.currentTarget.name == "leftTree") {
                    // folders cannot show thumbnail
                    // other file types than images are automatically not shown 
                    if (leftTree.selectedItem.@type == "file")
                        currentPhotoPath = SERVER_URL + leftTree.selectedItem.@path;
                    else
                        currentPhotoPath = "";
                // if click is on the list
                } else if (event.currentTarget.name == "downloadList") {
                    currentPhotoPath = (downloadList.selectedItem ? SERVER_URL + 
                                        downloadList.selectedItem.path : "");
                }
            }
 
            private function handleKeyUp(event:KeyboardEvent):void
            {
                /* this function is used for deleting items from the list */
 
                // if we have pressed the DELETE key and 
                // also there is at least one item selected
                if (event.keyCode == Keyboard.DELETE && downloadList.selectedIndex > -1) {
                    var removeItems:Array = downloadList.selectedIndices;
                    // remove selected items
                    for (var i:Number = 0; i < removeItems.length; i++) {
                        downloadList.dataProvider.removeItemAt(removeItems[i]);
                    }
                    currentPhotoPath = "";
                    // if the list is empty we disable the download button
                    if (downloadList.dataProvider.length <= 0)
                        downloadButton.enabled = false;
                }
            }
 
            private function initializeDownload(event:MouseEvent):void
            {
                /* this function starts the download 
                   we use FileReference to download */
 
                // get the items dragged in the list
                var paths:ArrayCollection = downloadList.dataProvider as ArrayCollection;
                // initialize the query/url string
                var qStr:String = "";
                // compose the query/url string
                // we are sending an array to the server
                for (var i:int = 0; i < paths.length; i++)
                    qStr += "&name[]="+escape(paths[i].path.toString());
                // get the file
                // the file download.php on the server gets the array
                // and in the memory creates an tgz archive
                // and sends it back as being a file (using http headers)
                // we are using FileReference for this
                fRef.download(new URLRequest(SERVER_URL + "download.php?" + qStr),"archive.tgz");
            }
 
            private function doEvent(evt:Event):void {
                /* Function is displaying events reached when downloading 
                   For debug purposes */
 
                var fr:FileReference = evt.currentTarget as FileReference;   
                // for debug purposes */
                //trace("type:"+evt.type+", eventString:"+evt.toString()); 
                //trace(fr.creationDate);
                //trace(fr.creator);
                //trace(fr.modificationDate);
                //trace(fr.name);
                //trace(fr.size);
                //trace(fr.type);
            } 		
 
            private function refresh(evt:Event):void {
                /* Function is refresing both the tree and the list and 
                   disables the download button */
 
                // empty the list
                downloadList.dataProvider = new ArrayCollection();
                // disable the download button
                downloadButton.enabled = false;
                // refresh the tree
                dir.send();
            }
        ]]>
    </mx:Script>
</mx:Application>

This is it! As I just wrote at the beginning of the article, the power and beauty of Flex framework is that you can do great things with a few lines of codding. So enjoy Flex!

Popularity: 100%

Share and Enjoy:
  • Technorati
  • StumbleUpon
  • del.icio.us
  • NewsVine
  • Reddit
  • Digg
  • Furl
  • co.mments
  • blogmarks
  • Slashdot
  • DZone
  • Taggly
  • YahooMyWeb
  • connotea
  • Webride
downloadapplication_sources_client-side
draganddrop
downloadapplication_server-side
downloadapplication_presentations




Tags: , , , , , ,

This post was written by Andrei Ionescu

Views: 2705

related

popular

1 Comment

have your say

Add your comment below, or trackback from your own site. Subscribe to these comments.

Be nice. Keep it clean. Stay on topic. No spam.

You can use these tags:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

:

:


« Override classes from included libraries
» Contributing to Flex 3 Cookbook