Fx{r} is trying to start the Fx{r} Community! Please join our group on Adobe Groups following this link: http://groups.adobe.com/groups/ab29539ab9.
Fx{r} is now on Twitter too. Follow us @ twitter.com/fx_r!
« 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

Andrei Ionescu | 12.05.08 | 7 Comments

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
<?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
                fileListProvider = 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!

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




Tags: , , , , , ,

This post was written by Andrei Ionescu

Views: 10438

related

7 Comments

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> <pre lang="" line="" escaped="">

:

:


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