| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package mx.utils |
| { |
| |
| import flash.filesystem.File; |
| import mx.collections.ArrayCollection; |
| import mx.collections.Sort; |
| |
| [ExcludeClass] |
| |
| /** |
| * @private |
| * |
| * The DirectoryEnumeration class supports filtering and sorting |
| * a list of File instances representing the files and directories |
| * in a file system directory. |
| * |
| */ |
| public class DirectoryEnumeration |
| { |
| include "../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @param source An Array of File instances representing |
| * the files and subdirectories in a file system directory. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function DirectoryEnumeration(source:Array = null) |
| { |
| super(); |
| |
| this.source = source; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * A hash table for looking up extensions quickly. |
| */ |
| private var extensionsSet:Object; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // collection |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var _collection:ArrayCollection; |
| |
| /** |
| * An ArrayCollection representing a filtered and sorted view |
| * of the <code>source</code> Array of File instances. |
| * The filtering is determined by the <code>enumerationMode</code>, |
| * <code>extensions</code>, <code>filterFunction</code> properties, |
| * and <code>showHidden</code> properties. |
| * The sorting is determined by the <code>enumerationMode</code> |
| * and <code>nameCompareFunction</code> properties. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get collection():ArrayCollection |
| { |
| return _collection; |
| } |
| |
| //---------------------------------- |
| // enumerationMode |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the enumerationMode property. |
| */ |
| private var _enumerationMode:String = |
| DirectoryEnumerationMode.DIRECTORIES_FIRST; |
| |
| /** |
| * A String specifying whether the <code>collection</code> |
| * includes only files, only subdirectories, or both. |
| * In the case that both are included, |
| * it also specifies whether the subdirectories are ordered |
| * before, after, or mixed in with the files. |
| * The possible values are specified |
| * by the DirectoryEnumerationMode class. |
| * |
| * <p>You must call <code>refresh()</code> after setting |
| * this property to change the <code>collection</code>.</p> |
| * |
| * <p>This property affects which subdirectories |
| * and files are in the <code>collection</code>. |
| * However, it does not affect which File instances |
| * are the <code>source</code> property; it works |
| * by changing the behavior of the <code>fileFilterFunction()</code> |
| * that is applied to the <code>source</code>.</p> |
| * |
| * @default DirectoryEnumerationMode.DIRECTORIES_FIRST |
| * |
| * @see mx.utils.DirectoryEnumerationMode |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get enumerationMode():String |
| { |
| return _enumerationMode; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set enumerationMode(value:String):void |
| { |
| _enumerationMode = value; |
| } |
| |
| //---------------------------------- |
| // extensions |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the extensions property. |
| */ |
| private var _extensions:Array /* of String */; |
| |
| /** |
| * An Array of extensions specifying which files |
| * are included in the <code>collection</code> |
| * If this property is set, for example, |
| * to <code>[ "htm", "html" ]</code>, |
| * then only files with these extensions are included. |
| * |
| * <p>Extensions are considered case-insensitive |
| * and the preceding dot is optional. |
| * For example, specifying <code>".HTML"</code> |
| * is equivalent to specifying <code>"html"</code>. </p> |
| * |
| * <p>Directories are not subject to extension filtering, |
| * even if they have names containing dots.</p> |
| * |
| * <p>The <code>enumerationMode</code> and <code>filterFunction</code> |
| * properties are also involved in determining which files |
| * are included in the <code>collection</code>. |
| * For example, if this property is <code>[ ".htm", ".html" ]</code>, |
| * an .html file will not be included if the |
| * <code>enumerationMode</code> property is |
| * <code>DirectoryEnumerationMode.DIRECTORIES_ONLY</code>, |
| * or if the <code>filterFunction</code> returns <code>false</code> |
| * for the file.</p> |
| * |
| * <p>If this property is <code>null</code>, no extension filtering |
| * occurs, and all files are included. |
| * If this property is an empty Array, all extensions are filtered out |
| * and no files with extensions are included.</p> |
| * |
| * <p>You must call <code>refresh()</code> after setting |
| * this property to change the <code>collection</code>.</p> |
| * |
| * <p>Although this property affects which files are included, |
| * it does not affect which File instances are in the |
| * <code>source</code> property; it works |
| * by changing the behavior of the <code>fileFilterFunction()</code> |
| * that is applied to the <code>source</code>.</p> |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get extensions():Array /* of String */ |
| { |
| return _extensions; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set extensions(value:Array /* of String */):void |
| { |
| _extensions = value; |
| |
| extensionsSet = {}; |
| for each (var s:String in extensions) |
| { |
| if (s.charAt(0) == ".") |
| s = s.substr(1); |
| extensionsSet[s.toLowerCase()] = true; |
| } |
| } |
| |
| //---------------------------------- |
| // filterFunction |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the filterFunction property. |
| */ |
| private var _filterFunction:Function; |
| |
| /** |
| * A callback Function that you can use to perform additional filtering, |
| * after the <code>enumerationMode</code> and <code>extensions</code> |
| * properties have been applied, to determine which files |
| * and subdirectories are included in the <code>collection</code>. |
| * |
| * <p>This function must have the following signature:</p> |
| * |
| * <pre>function myFilterFunction(file:File):Boolean</pre> |
| * |
| * <p>This function should return <code>true</code> to include |
| * the specified file or subdirectory.</p> |
| * |
| * <p>To ensure that every enumerated file and subdirectory is passed |
| * to this function, the <code>enumerationMode</code> property must |
| * not be <code>DirectoryEnumerationMode.FILES_ONLY</code> or |
| * <code>DirectoryEnumerationMode.DIRECTORIES_ONLY</code>, |
| * and the <code>extensions</code> property must be <code>null</code>. |
| * Otherwise, these properties will cause pre-filtering to occur |
| * before this filter function is called.</p> |
| * |
| * <p>You must call <code>refresh()</code> after setting |
| * this property to change the <code>collection</code>.</p> |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get filterFunction():Function |
| { |
| return _filterFunction; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set filterFunction(value:Function):void |
| { |
| _filterFunction = value; |
| } |
| |
| //---------------------------------- |
| // nameCompareFunction |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the nameCompareFunction property. |
| */ |
| private var _nameCompareFunction:Function; |
| |
| /** |
| * A callback Function that you can use to change how file and subdirectory |
| * names are compared in order to produce the sort order. |
| * |
| * <p>This function must have the following signature:</p> |
| * |
| * <pre>function myNameCompareFunction(name1:String, name2:String):int</pre> |
| * |
| * <p>It returns <code>-1</code> if <code>name1</code> should sort before |
| * <code>name2</code>, <code>1</code> if <code>name1</code> should |
| * sort after <code>name2</code>, and <code>0</code> if the names |
| * are the same.</p> |
| * |
| * <p>If you do not set this property, this class performs |
| * a case-insensitive, locale-dependent comparison of the two names, |
| * by first calling the String method <code>toLocaleLowerCase()</code> |
| * on each name and then comparing them with the <code><</code> |
| * and <code>></code> operators.</p> |
| * |
| * <p>If you have set <code>enumerationMode</code> to either |
| * <code>DirectoryEnumerationMode.FILES_FIRST</code> or |
| * <code>DirectoryEnumerationMode.DIRECTORIES_FIRST</code>, |
| * then this method will be used to compare names only within |
| * the separate groups of files and directories.</p> |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get nameCompareFunction():Function |
| { |
| return _nameCompareFunction; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set nameCompareFunction(value:Function):void |
| { |
| _nameCompareFunction = value; |
| } |
| |
| //---------------------------------- |
| // showHidden |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the showHidden property. |
| */ |
| private var _showHidden:Boolean = false; |
| |
| /** |
| * A flag that specifies whether files and directories |
| * that the operating system considers hidden |
| * are included in the <code>collection</code>. |
| * Set this property to <code>true</code> |
| * to include hidden files and directories. |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get showHidden():Boolean |
| { |
| return _showHidden; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set showHidden(value:Boolean):void |
| { |
| _showHidden = value; |
| } |
| |
| //---------------------------------- |
| // source |
| //---------------------------------- |
| |
| private var _source:Array /* of File */; |
| |
| /** |
| * The source of data for the <code>collection</code>. |
| * |
| * <p>This class expects this property to be set to an Array |
| * of File instances representing the files and directories |
| * in a single file system directory. |
| * You can obtain such an Array by calling the |
| * <code>listDirectory()</code> or <code>listDirectoryAsync()</code> |
| * of the File class.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get source():Array /* of File */ |
| { |
| return _source; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set source(value:Array /* of File */):void |
| { |
| _source = value; |
| |
| _collection = new ArrayCollection(source); |
| _collection.filterFunction = fileFilterFunction |
| _collection.sort = new Sort(); |
| _collection.sort.compareFunction = fileCompareFunction; |
| _collection.refresh(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Filters and sorts the <code>source</code> Array of File instances |
| * to produce the <code>collection</code>, as specified by the |
| * <code>enumerationMode</code>, <code>extensions</code>, |
| * <code>filterFunction</code>, <code>nameCompareFunction</code>, |
| * and <code>showHidden</code> properties. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function refresh():void |
| { |
| _collection.refresh(); |
| } |
| |
| /** |
| * The filter function that is actually applied to filter |
| * the <code>source</code Array to produce the <code>collection</code>. |
| * |
| * <p>At the end of its processing, this method calls your |
| * <code>filterFunction</code> if one is specified.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function fileFilterFunction(file:File):Boolean |
| { |
| // Some files like C:\pagefile.sys throw exceptions |
| // if a labelFunction tries to access other properties |
| // like size, creationDate, or modificationDate. |
| // Fortunately, these seem to have their 'exists' property |
| // set to false. |
| if (!file.exists) |
| return false; |
| |
| // Omit hidden files if showHidden is false. |
| // BUG WORKAROUND: Root directories like C:\ and D:\ |
| // have their hidden property set to true. |
| // Ignore it and show them. |
| if (!showHidden && file.isHidden && file.parent) |
| return false; |
| |
| // Omit all directories if "filesOnly" |
| // or all files if "directoriesOnly". |
| if (enumerationMode == DirectoryEnumerationMode.FILES_ONLY && |
| file.isDirectory || |
| enumerationMode == DirectoryEnumerationMode.DIRECTORIES_ONLY && |
| !file.isDirectory) |
| { |
| return false; |
| } |
| |
| // Now do extension-based filtering. |
| // Extension-filtering only occurs if the extensions property |
| // is non-null, and it only applies to files. |
| if (extensions && !file.isDirectory) |
| { |
| // If the file has no extension or that extension was not in |
| // the specified 'extensions' array, then filter out the file. |
| var extension:String = file.extension; |
| if (!extension || !extensionsSet[extension.toLowerCase()]) |
| return false; |
| } |
| |
| // Finally, do custom filtering. |
| return Boolean(filterFunction != null ? filterFunction(file) : true); |
| } |
| |
| /** |
| * The comparison function that is actually applied to sort |
| * the <code>source</code Array to produce the <code>collection</code>. |
| * |
| * <p>At the end of its processing, this method calls your |
| * <code>nameCompareFunction</code> if one is specified.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function fileCompareFunction(file1:File, file2:File, |
| fields:Array = null):int |
| { |
| if (file1.isDirectory && !file2.isDirectory) |
| { |
| if (enumerationMode == DirectoryEnumerationMode.DIRECTORIES_FIRST) |
| return -1; |
| if (enumerationMode == DirectoryEnumerationMode.FILES_FIRST) |
| return 1; |
| } |
| |
| if (!file1.isDirectory && file2.isDirectory) |
| { |
| if (enumerationMode == DirectoryEnumerationMode.DIRECTORIES_FIRST) |
| return 1; |
| if (enumerationMode == DirectoryEnumerationMode.FILES_FIRST) |
| return -1; |
| } |
| |
| return nameCompareFunction != null ? |
| nameCompareFunction(file1.name, file2.name) : |
| defaultNameCompareFunction(file1.name, file2.name); |
| } |
| |
| /** |
| * Performs a case-insensitive, locale-dependent comparison |
| * of two file or directory names, using the String method |
| * <code>toLocaleLowerCase()</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function defaultNameCompareFunction(name1:String, name2:String):int |
| { |
| name1 = name1.toLocaleLowerCase(); |
| name2 = name2.toLocaleLowerCase(); |
| |
| if (name1 < name2) |
| return -1; |
| |
| if (name1 > name2) |
| return 1; |
| |
| return 0; |
| } |
| } |
| |
| } |