| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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.controls.fileSystemClasses |
| { |
| |
| import flash.events.Event; |
| import flash.events.KeyboardEvent; |
| import flash.filesystem.File; |
| import flash.system.Capabilities; |
| import flash.ui.Keyboard; |
| import mx.collections.ArrayCollection; |
| import mx.controls.FileSystemEnumerationMode; |
| import mx.controls.dataGridClasses.DataGridColumn; |
| import mx.core.mx_internal; |
| import mx.events.FileEvent; |
| import mx.events.FlexEvent; |
| import mx.events.ListEvent; |
| import mx.resources.IResourceManager; |
| import mx.resources.ResourceManager; |
| import mx.utils.DirectoryEnumeration; |
| |
| use namespace mx_internal; |
| |
| [ExcludeClass] |
| |
| /** |
| * @private |
| */ |
| public class FileSystemControlHelper |
| { |
| include "../../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class initialization |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| public static var COMPUTER:File; |
| |
| /** |
| * @private |
| */ |
| private static function initClass():void |
| { |
| if (Capabilities.os.substring(0, 3) == "Win") |
| COMPUTER = new File("root$:\\Computer"); |
| else // Mac or Unix |
| COMPUTER = new File("/Computer"); |
| } |
| |
| initClass(); |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private static function fileSystemIsCaseInsensitive():Boolean |
| { |
| var os:String = Capabilities.os.substring(0, 3); |
| return os == "Win" || os == "Mac"; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function FileSystemControlHelper(owner:Object, hierarchical:Boolean) |
| { |
| super(); |
| |
| this.owner = owner; |
| this.hierarchical = hierarchical; |
| |
| owner.addEventListener(FlexEvent.UPDATE_COMPLETE, |
| updateCompleteHandler); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * A reference to the FileSystemList, FileSystemDataGrid, |
| * FileSystemTree, or FileSystemComboBox using this object. |
| */ |
| mx_internal var owner:Object; |
| |
| /** |
| * @private |
| * A flag indicating whether the dataProvider of the owner |
| * is hierarchical or flat. |
| * In other words, this flag is true if the owner |
| * is a FileSystemTree and false otherwise. |
| */ |
| mx_internal var hierarchical:Boolean; |
| |
| /** |
| * @private |
| */ |
| mx_internal var resourceManager:IResourceManager = |
| ResourceManager.getInstance(); |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // backHistory |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| public function get backHistory():Array |
| { |
| return historyIndex > 0 ? |
| history.slice(0, historyIndex).reverse() : |
| []; |
| } |
| |
| //---------------------------------- |
| // canNavigateBack |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| public function get canNavigateBack():Boolean |
| { |
| return historyIndex > 0; |
| } |
| |
| //---------------------------------- |
| // canNavigateDown |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| public function get canNavigateDown():Boolean |
| { |
| var selectedFile:File = File(owner.selectedItem); |
| return selectedFile && selectedFile.isDirectory; |
| } |
| |
| //---------------------------------- |
| // canNavigateForward |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| public function get canNavigateForward():Boolean |
| { |
| return historyIndex < history.length - 1; |
| } |
| |
| //---------------------------------- |
| // canNavigateUp |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| public function get canNavigateUp():Boolean |
| { |
| return !isComputer(directory); |
| } |
| |
| //---------------------------------- |
| // directory |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the directory property. |
| */ |
| private var _directory:File; |
| |
| /** |
| * @private |
| */ |
| private var directoryChanged:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| public function get directory():File |
| { |
| return _directory; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set directory(value:File):void |
| { |
| if (!value || |
| (!isComputer(value) && |
| (!value.exists || !value.isDirectory))) |
| { |
| throw(new Error("No such directory: " + value.nativePath)); |
| } |
| |
| resetHistory(value); |
| |
| setDirectory(value); |
| } |
| |
| //---------------------------------- |
| // directoryEnumeration |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| mx_internal var directoryEnumeration:DirectoryEnumeration = |
| new DirectoryEnumeration(); |
| |
| //---------------------------------- |
| // enumerationMode |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the enumerationMode property. |
| */ |
| private var _enumerationMode:String = |
| FileSystemEnumerationMode.DIRECTORIES_FIRST; |
| |
| /** |
| * @private |
| */ |
| private var enumerationModeChanged:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| public function get enumerationMode():String |
| { |
| return _enumerationMode; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set enumerationMode(value:String):void |
| { |
| _enumerationMode = value; |
| enumerationModeChanged = true; |
| |
| owner.invalidateProperties(); |
| } |
| |
| //---------------------------------- |
| // extensions |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the extensions property. |
| */ |
| private var _extensions:Array /* of String */; |
| |
| /** |
| * @private |
| */ |
| private var extensionsChanged:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| public function get extensions():Array /* of String */ |
| { |
| return _extensions; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set extensions(value:Array /* of String */):void |
| { |
| _extensions = value; |
| extensionsChanged = true; |
| |
| owner.invalidateProperties(); |
| } |
| |
| //---------------------------------- |
| // filterFunction |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the filterFunction property. |
| */ |
| private var _filterFunction:Function; |
| |
| /** |
| * @private |
| */ |
| private var filterFunctionChanged:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| public function get filterFunction():Function |
| { |
| return _filterFunction; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set filterFunction(value:Function):void |
| { |
| _filterFunction = value; |
| filterFunctionChanged = true; |
| |
| owner.invalidateProperties(); |
| } |
| |
| //---------------------------------- |
| // forwardHistory |
| //---------------------------------- |
| |
| [Bindable("historyChanged")] |
| |
| /** |
| * @private |
| */ |
| public function get forwardHistory():Array |
| { |
| return historyIndex < history.length - 1 ? |
| history.slice(historyIndex + 1) : |
| []; |
| } |
| |
| //---------------------------------- |
| // history |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| public var history:Array; |
| |
| //---------------------------------- |
| // historyIndex |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| public var historyIndex:int; |
| |
| //---------------------------------- |
| // nativePathToIndexMap |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the nativePathToIndexMap property. |
| */ |
| private var _nativePathToIndexMap:Object; |
| |
| /** |
| * @private |
| * Maps nativePath (String) -> index (int). |
| * This map is used to implement findIndex() as a simple lookup, |
| * so that multiple finds are fast. |
| * It is freed whenever an operation changes which items |
| * are displayed in the control, or their order, |
| * and rebuilt tne next time it or <code>items</code> is accessed. |
| */ |
| mx_internal function get nativePathToIndexMap():Object |
| { |
| if (!_nativePathToIndexMap) |
| rebuildEnumerationInfo(); |
| |
| return _nativePathToIndexMap; |
| } |
| |
| //---------------------------------- |
| // itemArray |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the itemArray property. |
| */ |
| private var _itemArray:Array /* of File */; |
| |
| /** |
| * @private |
| * An array of all the File items displayed in the control, |
| * in the order in which they appear. |
| * This array is used together with <code>nativePathToIndexMap</code> |
| * to implement findItem() as a simple lookup, |
| * so that multiple finds are fast. |
| * It is freed whenever an operation changes which items |
| * are displayed in the control, or their order, |
| * and rebuilt tne next time it |
| * or <code>nativePathToIndexMap</code> is accessed. |
| */ |
| mx_internal function get itemArray():Array /* of File */ |
| { |
| if (!_itemArray) |
| rebuildEnumerationInfo(); |
| |
| return _itemArray; |
| } |
| |
| //---------------------------------- |
| // nameCompareFunction |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the nameCompareFunction property. |
| */ |
| private var _nameCompareFunction:Function; |
| |
| /** |
| * @private |
| */ |
| private var nameCompareFunctionChanged:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| public function get nameCompareFunction():Function |
| { |
| return _nameCompareFunction; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set nameCompareFunction(value:Function):void |
| { |
| _nameCompareFunction = value; |
| nameCompareFunctionChanged = true; |
| |
| owner.invalidateProperties(); |
| } |
| |
| //---------------------------------- |
| // openPaths |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var pendingOpenPaths:Array /* of String */; |
| |
| /** |
| * An Array of <code>nativePath</code> Strings for the File items |
| * representing the open subdirectories. |
| * This Array is empty if no subdirectories are open. |
| * |
| * @default [] |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get openPaths():Array /* of String */ |
| { |
| return pendingOpenPaths ? |
| pendingOpenPaths : |
| getOpenPaths(); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set openPaths(value:Array /* of String */):void |
| { |
| pendingOpenPaths = value; |
| |
| owner.invalidateProperties(); |
| } |
| |
| //---------------------------------- |
| // selectedPath |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| public function get selectedPath():String |
| { |
| return selectedPaths[0]; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedPath(value:String):void |
| { |
| selectedPaths = [ value ]; |
| } |
| |
| //---------------------------------- |
| // selectedPaths |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var pendingSelectedPaths:Array /* of String */; |
| |
| /** |
| * @private |
| */ |
| public function get selectedPaths():Array /* of String */ |
| { |
| return pendingSelectedPaths ? |
| pendingSelectedPaths : |
| getSelectedPaths(); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedPaths(value:Array /* of String */):void |
| { |
| pendingSelectedPaths = value; |
| |
| owner.invalidateProperties(); |
| } |
| |
| //---------------------------------- |
| // showExtensions |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the showExtensions property. |
| */ |
| private var _showExtensions:Boolean = true; |
| |
| /** |
| * @private |
| */ |
| public function get showExtensions():Boolean |
| { |
| return _showExtensions; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set showExtensions(value:Boolean):void |
| { |
| _showExtensions = value; |
| |
| owner.invalidateList(); |
| } |
| |
| //---------------------------------- |
| // showHidden |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the showHidden property. |
| */ |
| private var _showHidden:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| private var showHiddenChanged:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| public function get showHidden():Boolean |
| { |
| return _showHidden; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set showHidden(value:Boolean):void |
| { |
| _showHidden = value; |
| showHiddenChanged = true; |
| |
| owner.invalidateProperties(); |
| } |
| |
| //---------------------------------- |
| // showIcons |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the showIcons property. |
| */ |
| private var _showIcons:Boolean = true; |
| |
| /** |
| * @private |
| */ |
| public function get showIcons():Boolean |
| { |
| return _showIcons; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set showIcons(value:Boolean):void |
| { |
| _showIcons = value; |
| |
| owner.invalidateList(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| public function commitProperties():void |
| { |
| if (enumerationModeChanged || |
| extensionsChanged || |
| filterFunctionChanged || |
| nameCompareFunctionChanged || |
| showHiddenChanged) |
| { |
| directoryEnumeration.enumerationMode = enumerationMode; |
| directoryEnumeration.extensions = extensions; |
| directoryEnumeration.filterFunction = filterFunction; |
| directoryEnumeration.nameCompareFunction = nameCompareFunction; |
| directoryEnumeration.showHidden = showHidden; |
| directoryEnumeration.refresh(); |
| |
| // For a List or DataGrid, refreshing its collection |
| // (which is what directoryEnumeration.refresh() does) |
| // is enough to make the control update properly |
| // with the newly filtered/sorted collection. |
| // But a Tree doesn't properly handle having its |
| // collection refreshed; for example, if the new |
| // filter reduces the number of items, the Tree |
| // can display blank renderers. |
| // So instead we simply reset the dataProvider. |
| owner.dataProvider = directoryEnumeration.collection; |
| |
| itemsChanged(); |
| |
| extensionsChanged = false; |
| enumerationModeChanged = false; |
| filterFunctionChanged = false; |
| nameCompareFunctionChanged = false; |
| showHiddenChanged = false; |
| } |
| |
| if (directoryChanged) |
| { |
| fill(); |
| |
| var event:FileEvent = new FileEvent(FileEvent.DIRECTORY_CHANGE); |
| event.file = directory; |
| owner.dispatchEvent(event); |
| |
| directoryChanged = false; |
| } |
| } |
| |
| /** |
| * Fills the list by enumerating the current directory |
| * and setting the dataProvider. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| mx_internal function fill():void |
| { |
| setDataProvider(isComputer(directory) ? |
| getRootDirectories() : |
| directory.getDirectoryListing()); |
| } |
| |
| /** |
| * @private |
| */ |
| public function styleChanged(styleProp:String):void |
| { |
| if (styleProp == "fileIcon" || styleProp == "directoryIcon") |
| owner.invalidateList(); |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function setDirectory(value:File):void |
| { |
| _directory = value; |
| directoryChanged = true; |
| |
| // Clear the now-stale contents of the list. |
| // The list will repopulate after the new directory |
| // is enumerated. |
| owner.dataProvider = null; |
| |
| if (hierarchical) |
| owner.dataDescriptor.reset(); |
| |
| owner.invalidateProperties(); |
| |
| // Trigger databindings. |
| owner.dispatchEvent(new Event("directoryChanged")); |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function setDataProvider(value:Array):void |
| { |
| directoryEnumeration.enumerationMode = enumerationMode; |
| directoryEnumeration.extensions = extensions; |
| directoryEnumeration.filterFunction = filterFunction; |
| directoryEnumeration.nameCompareFunction = nameCompareFunction; |
| directoryEnumeration.showHidden = showHidden; |
| |
| directoryEnumeration.source = value; |
| |
| owner.dataProvider = directoryEnumeration.collection; |
| |
| itemsChanged(); |
| } |
| |
| /** |
| * @private |
| */ |
| public function itemToUID(data:Object):String |
| { |
| return data ? File(data).nativePath : "null"; |
| } |
| |
| /** |
| * @private |
| */ |
| public function isComputer(f:File):Boolean |
| { |
| if (Capabilities.os.substr(0, 3) =="Win") |
| return f.nativePath.substring(0, 6) == "root$:"; |
| return f.nativePath == "/Computer"; |
| } |
| |
| /** |
| * @private |
| */ |
| private function getRootDirectories():Array |
| { |
| var a:Array = []; |
| |
| for each (var f:File in File.getRootDirectories()) |
| { |
| if (f.isDirectory) |
| a.push(f); |
| } |
| |
| return a; |
| } |
| |
| /** |
| * @private |
| */ |
| public function fileIconFunction(item:File):Class |
| { |
| if (!showIcons) |
| return null; |
| |
| return owner.getStyle(item.isDirectory ? "directoryIcon" : "fileIcon"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function fileLabelFunction(item:File, |
| column:DataGridColumn = null):String |
| { |
| if (isComputer(item)) |
| { |
| return resourceManager.getString( |
| "aircontrols", "computer"); |
| } |
| |
| var label:String = item.name; |
| |
| // The name of the / directory on Mac is the empty string. |
| // In this case, display the nativePath, which will be "/". |
| if (label == "") |
| label = item.nativePath; |
| |
| if (!item.isDirectory && !showExtensions) |
| { |
| var index:int = label.lastIndexOf("."); |
| if (index != -1) |
| label = label.substring(0, index); |
| } |
| |
| return label; |
| } |
| |
| /** |
| * @private |
| */ |
| public function findIndex(nativePath:String):int |
| { |
| if (!nativePath) |
| return -1; |
| |
| if (fileSystemIsCaseInsensitive()) |
| nativePath = nativePath.toLowerCase(); |
| |
| var value:* = nativePathToIndexMap[nativePath]; |
| return value === undefined ? -1 : int(value); |
| } |
| |
| /** |
| * @private |
| */ |
| public function findItem(nativePath:String):File |
| { |
| var index:int = findIndex(nativePath); |
| if (index == -1) |
| return null; |
| |
| return itemArray[index]; |
| } |
| |
| /** |
| * @private |
| * This method is called whenever something happens |
| * that affects which items are displayed by the |
| * control, or the order in which they are displayed. |
| */ |
| mx_internal function itemsChanged():void |
| { |
| // These two data structures are now invalid, so free them. |
| // They will be rebuilt the next time they are needed. |
| _itemArray = null; |
| _nativePathToIndexMap = null; |
| } |
| |
| /** |
| * @private |
| */ |
| private function rebuildEnumerationInfo():void |
| { |
| _itemArray = []; |
| _nativePathToIndexMap = {}; |
| |
| enumerateItems(addItemToEnumerationInfo); |
| } |
| |
| /** |
| * @private |
| */ |
| private function addItemToEnumerationInfo(index:int, item:File):void |
| { |
| var nativePath:String = item.nativePath; |
| |
| if (fileSystemIsCaseInsensitive()) |
| nativePath = nativePath.toLowerCase(); |
| |
| _itemArray.push(item); |
| _nativePathToIndexMap[nativePath] = index; |
| } |
| |
| /** |
| * @private |
| */ |
| private function enumerateItems(itemCallback:Function):int |
| { |
| return enumerate(ArrayCollection(owner.dataProvider), |
| 0, itemCallback); |
| } |
| |
| /** |
| * @private |
| */ |
| private function enumerate(items:ArrayCollection, index:int, |
| itemCallback:Function):int |
| { |
| var n:int = items.length; |
| for (var i:int = 0; i < n; i++) |
| { |
| var item:File = File(items.getItemAt(i)); |
| itemCallback(index, item); |
| index++; |
| |
| if (hierarchical && item.isDirectory && owner.isItemOpen(item)) |
| { |
| var childItems:ArrayCollection = |
| owner.dataDescriptor.getChildren(item); |
| |
| index = enumerate(childItems, index, itemCallback); |
| } |
| } |
| return index; |
| } |
| |
| /** |
| * @private |
| */ |
| public function navigateDown():void |
| { |
| if (canNavigateDown) |
| navigateTo(File(owner.selectedItem)); |
| } |
| |
| /** |
| * @private |
| */ |
| public function navigateUp():void |
| { |
| if (canNavigateUp) |
| navigateTo(directory.parent ? directory.parent : COMPUTER); |
| } |
| |
| /** |
| * @private |
| */ |
| public function navigateBack(index:int = 0):void |
| { |
| if (canNavigateBack) |
| navigateBy(-1 - index); |
| } |
| |
| /** |
| * @private |
| */ |
| public function navigateForward(index:int = 0):void |
| { |
| if (canNavigateForward) |
| navigateBy(1 + index) |
| } |
| |
| /** |
| * @private |
| */ |
| private function navigateBy(n:int):void |
| { |
| historyIndex += n; |
| |
| if (historyIndex < 0) |
| historyIndex = 0; |
| else if (historyIndex > history.length - 1) |
| historyIndex = history.length - 1; |
| |
| setDirectory(history[historyIndex]); |
| |
| owner.dispatchEvent(new Event("historyChanged")); |
| } |
| |
| /** |
| * @private |
| */ |
| public function navigateTo(directory:File):void |
| { |
| setDirectory(directory); |
| |
| pushHistory(directory); |
| } |
| |
| /** |
| * @private |
| */ |
| public function refresh():void |
| { |
| var openPaths:Array /* of String */ |
| var selectedPaths:Array /* of String */; |
| var firstVisiblePath:String; |
| var oldHorizontalScrollPosition:int; |
| |
| if (hierarchical) |
| openPaths = getOpenPaths(); |
| selectedPaths = getSelectedPaths(); |
| firstVisiblePath = getFirstVisiblePath(); |
| oldHorizontalScrollPosition = owner.horizontalScrollPosition; |
| |
| fill(); |
| |
| // Tree must be revalidated after its dataProvider |
| // changes for expandItem() to work. |
| if (hierarchical) |
| owner.validateNow(); |
| |
| if (hierarchical) |
| setOpenPaths(openPaths); |
| setSelectedPaths(selectedPaths); |
| if (setFirstVisiblePath(firstVisiblePath)) |
| owner.horizontalScrollPosition = oldHorizontalScrollPosition; |
| } |
| |
| /** |
| * @private |
| */ |
| private function getOpenPaths():Array /* of String */ |
| { |
| var openPaths:Array /* of String */ = []; |
| var n:int = owner.openItems.length; |
| for (var i:int = 0; i < n; i++) |
| { |
| openPaths.push(File(owner.openItems[i]).nativePath); |
| } |
| return openPaths; |
| } |
| |
| /** |
| * @private |
| * Returns an Array of nativePath Strings for the selected items. |
| * This method is called by refresh() before repopulating the control. |
| */ |
| private function getSelectedPaths():Array /* of String */ |
| { |
| var selectedPaths:Array /* of String */ = []; |
| var n:int = owner.selectedItems.length; |
| for (var i:int = 0; i < n; i++) |
| { |
| selectedPaths.push(File(owner.selectedItems[i]).nativePath); |
| } |
| return selectedPaths; |
| } |
| |
| /** |
| * @private |
| * Returns the nativePath of the first visible item. |
| * This method is called by refresh() before repopulating the control. |
| */ |
| private function getFirstVisiblePath():String |
| { |
| if (owner.dataProvider == null || owner.dataProvider.length == 0) |
| return null; |
| |
| var index:int = owner.verticalScrollPosition; |
| var item:File = itemArray[index]; |
| return item ? item.nativePath : null; |
| } |
| |
| /** |
| * @private |
| */ |
| private function setOpenPaths(openPaths:Array /* of String */):void |
| { |
| var n:int = openPaths.length; |
| for (var i:int = 0; i < n; i++) |
| { |
| owner.openSubdirectory(openPaths[i]); |
| } |
| } |
| |
| /** |
| * @private |
| * Selects items whose nativePaths are in the specified Array. |
| * This method is called by refresh() after repopulating the control. |
| */ |
| private function setSelectedPaths(selectedPaths:Array /* of String */):void |
| { |
| var indices:Array /* of int */ = []; |
| |
| var n:int = selectedPaths.length; |
| for (var i:int = 0; i < n; i++) |
| { |
| var path:String = selectedPaths[i]; |
| var index:int = findIndex(path); |
| if (index != -1) |
| indices.push(index); |
| } |
| |
| owner.selectedIndices = indices; |
| } |
| |
| /** |
| * @private |
| * Scrolls the list to the item with the specified nativePath. |
| * This method is by refresh() after repopulating the control. |
| */ |
| private function setFirstVisiblePath(path:String):Boolean |
| { |
| if (path == null) |
| return false; |
| |
| var index:int = findIndex(path); |
| if (index == -1) |
| return false; |
| |
| owner.verticalScrollPosition = index; |
| return true; |
| } |
| |
| /** |
| * @private |
| */ |
| public function clear():void |
| { |
| owner.dataProvider = null; |
| |
| itemsChanged(); |
| } |
| |
| /** |
| * @private |
| */ |
| public function resetHistory(directory:File):void |
| { |
| history = [ directory ]; |
| historyIndex = 0; |
| |
| owner.dispatchEvent(new Event("historyChanged")); |
| } |
| |
| /** |
| * @private |
| */ |
| private function pushHistory(directory:File):void |
| { |
| historyIndex++; |
| history.splice(historyIndex); |
| history.push(directory); |
| |
| owner.dispatchEvent(new Event("historyChanged")); |
| } |
| |
| /** |
| * @private |
| * Returns an Array of File objects |
| * representing the path to the specified directory. |
| * The first File represents a root directory. |
| * The last File represents the specified file's parent directory. |
| */ |
| public function getParentChain(file:File):Array |
| { |
| if (!file) |
| return []; |
| |
| var a:Array = []; |
| |
| for (var f:File = file; f != null; f = f.parent) |
| { |
| a.unshift(f); |
| } |
| |
| return a; |
| } |
| |
| /** |
| * @private |
| * Dispatches a cancelable "directoryChanging" event |
| * and returns true if it wasn't canceled. |
| */ |
| mx_internal function dispatchDirectoryChangingEvent(newDirectory:File):Boolean |
| { |
| var event:FileEvent = |
| new FileEvent(FileEvent.DIRECTORY_CHANGING, false, true); |
| event.file = newDirectory; |
| owner.dispatchEvent(event); |
| |
| return !event.isDefaultPrevented(); |
| } |
| |
| /** |
| * @private |
| * Dispatches a "fileChoose" event. |
| */ |
| mx_internal function dispatchFileChooseEvent(file:File):void |
| { |
| var event:FileEvent = new FileEvent(FileEvent.FILE_CHOOSE); |
| event.file = file; |
| owner.dispatchEvent(event); |
| } |
| |
| /** |
| * @private |
| */ |
| private function getBackDirectory():File |
| { |
| return historyIndex == 0 ? |
| null : |
| history[historyIndex - 1]; |
| } |
| |
| /** |
| * @private |
| */ |
| private function getForwardDirectory():File |
| { |
| return historyIndex == history.length - 1 ? |
| null : |
| history[historyIndex + 1]; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private function updateCompleteHandler(event:FlexEvent):void |
| { |
| if (pendingOpenPaths != null) |
| { |
| setOpenPaths(pendingOpenPaths); |
| |
| pendingOpenPaths = null; |
| } |
| |
| if (pendingSelectedPaths != null) |
| { |
| setSelectedPaths(pendingSelectedPaths); |
| |
| pendingSelectedPaths = null; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| public function itemDoubleClickHandler(event:ListEvent):void |
| { |
| var selectedFile:File = File(owner.selectedItem); |
| |
| if (selectedFile.isDirectory) |
| { |
| if (dispatchDirectoryChangingEvent(selectedFile)) |
| navigateDown(); |
| } |
| else |
| { |
| dispatchFileChooseEvent(selectedFile); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| public function handleKeyDown(event:KeyboardEvent):Boolean |
| { |
| switch (event.keyCode) |
| { |
| case Keyboard.ENTER: |
| { |
| var selectedFile:File = File(owner.selectedItem); |
| |
| if (canNavigateDown && |
| dispatchDirectoryChangingEvent(selectedFile)) |
| { |
| navigateDown(); |
| } |
| else |
| { |
| dispatchFileChooseEvent(selectedFile); |
| } |
| return true; |
| } |
| |
| case Keyboard.BACKSPACE: |
| { |
| if (canNavigateUp && |
| dispatchDirectoryChangingEvent(directory.parent)) |
| { |
| navigateUp(); |
| } |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| } |
| |
| } |