//////////////////////////////////////////////////////////////////////////////// // // 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 source Array of File instances. * The filtering is determined by the enumerationMode, * extensions, filterFunction properties, * and showHidden properties. * The sorting is determined by the enumerationMode * and nameCompareFunction 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 collection * 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. * *

You must call refresh() after setting * this property to change the collection.

* *

This property affects which subdirectories * and files are in the collection. * However, it does not affect which File instances * are the source property; it works * by changing the behavior of the fileFilterFunction() * that is applied to the source.

* * @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 collection * If this property is set, for example, * to [ "htm", "html" ], * then only files with these extensions are included. * *

Extensions are considered case-insensitive * and the preceding dot is optional. * For example, specifying ".HTML" * is equivalent to specifying "html".

* *

Directories are not subject to extension filtering, * even if they have names containing dots.

* *

The enumerationMode and filterFunction * properties are also involved in determining which files * are included in the collection. * For example, if this property is [ ".htm", ".html" ], * an .html file will not be included if the * enumerationMode property is * DirectoryEnumerationMode.DIRECTORIES_ONLY, * or if the filterFunction returns false * for the file.

* *

If this property is null, 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.

* *

You must call refresh() after setting * this property to change the collection.

* *

Although this property affects which files are included, * it does not affect which File instances are in the * source property; it works * by changing the behavior of the fileFilterFunction() * that is applied to the source.

* * @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 enumerationMode and extensions * properties have been applied, to determine which files * and subdirectories are included in the collection. * *

This function must have the following signature:

* *
function myFilterFunction(file:File):Boolean
* *

This function should return true to include * the specified file or subdirectory.

* *

To ensure that every enumerated file and subdirectory is passed * to this function, the enumerationMode property must * not be DirectoryEnumerationMode.FILES_ONLY or * DirectoryEnumerationMode.DIRECTORIES_ONLY, * and the extensions property must be null. * Otherwise, these properties will cause pre-filtering to occur * before this filter function is called.

* *

You must call refresh() after setting * this property to change the collection.

* * @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. * *

This function must have the following signature:

* *
function myNameCompareFunction(name1:String, name2:String):int
* *

It returns -1 if name1 should sort before * name2, 1 if name1 should * sort after name2, and 0 if the names * are the same.

* *

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 toLocaleLowerCase() * on each name and then comparing them with the < * and > operators.

* *

If you have set enumerationMode to either * DirectoryEnumerationMode.FILES_FIRST or * DirectoryEnumerationMode.DIRECTORIES_FIRST, * then this method will be used to compare names only within * the separate groups of files and directories.

* * @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 collection. * Set this property to true * 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 collection. * *

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 * listDirectory() or listDirectoryAsync() * of the File class.

* * @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 source Array of File instances * to produce the collection, as specified by the * enumerationMode, extensions, * filterFunction, nameCompareFunction, * and showHidden 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 sourcecollection. * *

At the end of its processing, this method calls your * filterFunction if one is specified.

* * @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 sourcecollection. * *

At the end of its processing, this method calls your * nameCompareFunction if one is specified.

* * @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 * toLocaleLowerCase(). * * @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; } } }