blob: 4f2ddd8996db5f51b8458c7451120f01194dd39b [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// 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>&lt;</code>
* and <code>&gt;</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;
}
}
}