├── README.md ├── key.p12 ├── libs ├── puremvc.swc ├── bellonalib.swc └── Windows8UIStyle.swc ├── SpaceSnifferAnywhere.air ├── screenCapture ├── QQ截图20140217170619.png ├── QQ截图20140217170815.png ├── QQ截图20140217170908.png └── QQ截图20140217170945.png ├── tmp └── Components2(TransitionStyle).swc ├── src ├── Global.as ├── org │ └── marz │ │ ├── sys │ │ ├── CmdSys.as │ │ ├── worker │ │ │ ├── InitWorker.as │ │ │ ├── WorkerSide.as │ │ │ └── MainSide.as │ │ ├── Init.as │ │ └── OnEnterFrame.as │ │ └── spaceSniffer │ │ ├── c │ │ ├── Refresh.as │ │ ├── InitWorkSpaceUI.as │ │ └── ExploreFileTree.as │ │ ├── worker │ │ ├── LaunchScan.as │ │ └── WorkerReady.as │ │ ├── m │ │ ├── GridsProxy.as │ │ └── vo │ │ │ └── FileTree.as │ │ └── v │ │ ├── PickVolumeMediator.as │ │ ├── GridsMediator.as │ │ └── vo │ │ └── GridRenderer.as ├── StartupProxy.as ├── SpaceSniffer.as ├── Startup.as └── SpaceSniffer-app.xml ├── .gitignore ├── .project └── .actionScriptProperties /README.md: -------------------------------------------------------------------------------- 1 | SpaceSniffer 2 | ============ 3 | 跨平台的SpaceSniffer 4 | -------------------------------------------------------------------------------- /key.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marzwu/SpaceSniffer/HEAD/key.p12 -------------------------------------------------------------------------------- /libs/puremvc.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marzwu/SpaceSniffer/HEAD/libs/puremvc.swc -------------------------------------------------------------------------------- /libs/bellonalib.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marzwu/SpaceSniffer/HEAD/libs/bellonalib.swc -------------------------------------------------------------------------------- /SpaceSnifferAnywhere.air: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marzwu/SpaceSniffer/HEAD/SpaceSnifferAnywhere.air -------------------------------------------------------------------------------- /libs/Windows8UIStyle.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marzwu/SpaceSniffer/HEAD/libs/Windows8UIStyle.swc -------------------------------------------------------------------------------- /screenCapture/QQ截图20140217170619.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marzwu/SpaceSniffer/HEAD/screenCapture/QQ截图20140217170619.png -------------------------------------------------------------------------------- /screenCapture/QQ截图20140217170815.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marzwu/SpaceSniffer/HEAD/screenCapture/QQ截图20140217170815.png -------------------------------------------------------------------------------- /screenCapture/QQ截图20140217170908.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marzwu/SpaceSniffer/HEAD/screenCapture/QQ截图20140217170908.png -------------------------------------------------------------------------------- /screenCapture/QQ截图20140217170945.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marzwu/SpaceSniffer/HEAD/screenCapture/QQ截图20140217170945.png -------------------------------------------------------------------------------- /tmp/Components2(TransitionStyle).swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marzwu/SpaceSniffer/HEAD/tmp/Components2(TransitionStyle).swc -------------------------------------------------------------------------------- /src/Global.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.display.Stage; 4 | 5 | public class Global 6 | { 7 | public static var stage:Stage; 8 | 9 | public function Global() 10 | { 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/org/marz/sys/CmdSys.as: -------------------------------------------------------------------------------- 1 | package org.marz.sys 2 | { 3 | public class CmdSys 4 | { 5 | public static const ENTER_FRAME:String = 'enterFrame'; 6 | 7 | public function CmdSys() 8 | { 9 | ENTER_FRAME 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build and Release Folders 2 | bin/ 3 | bin-debug/ 4 | bin-release/ 5 | 6 | # Other files and folders 7 | .settings/ 8 | 9 | # Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` 10 | # should NOT be excluded as they contain compiler settings and other important 11 | # information for Eclipse / Flash Builder. 12 | -------------------------------------------------------------------------------- /src/org/marz/spaceSniffer/c/Refresh.as: -------------------------------------------------------------------------------- 1 | package org.marz.spaceSniffer.c 2 | { 3 | import org.marz.spaceSniffer.v.GridsMediator; 4 | import org.puremvc.as3.patterns.facade.Facade; 5 | 6 | public class Refresh 7 | { 8 | public function Refresh() 9 | { 10 | } 11 | 12 | public static function doRefresh():void 13 | { 14 | Facade.getInstance().sendNotification(GridsMediator.UPDATE); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/org/marz/sys/worker/InitWorker.as: -------------------------------------------------------------------------------- 1 | package org.marz.sys.worker 2 | { 3 | import org.puremvc.as3.interfaces.INotification; 4 | import org.puremvc.as3.patterns.command.SimpleCommand; 5 | 6 | public class InitWorker extends SimpleCommand 7 | { 8 | override public function execute(notification:INotification):void 9 | { 10 | // TODO Auto Generated method stub 11 | super.execute(notification); 12 | } 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /src/StartupProxy.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.display.Stage; 4 | 5 | import org.puremvc.as3.patterns.facade.Facade; 6 | import org.puremvc.as3.patterns.proxy.Proxy; 7 | 8 | public class StartupProxy extends Proxy 9 | { 10 | private static const NAME:String = 'StartupProxy'; 11 | 12 | public function StartupProxy() 13 | { 14 | super(NAME, null); 15 | } 16 | 17 | public static function get instance():StartupProxy 18 | { 19 | return StartupProxy(Facade.getInstance().retrieveProxy(NAME)); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/org/marz/spaceSniffer/worker/LaunchScan.as: -------------------------------------------------------------------------------- 1 | package org.marz.spaceSniffer.worker 2 | { 3 | import flash.filesystem.File; 4 | 5 | import org.marz.spaceSniffer.m.vo.FileTree; 6 | import org.marz.sys.worker.WorkerSide; 7 | 8 | public class LaunchScan 9 | { 10 | public function LaunchScan() 11 | { 12 | } 13 | 14 | public static function launch(args:Array):void 15 | { 16 | var b:File = new File; 17 | var file:File = new File(args[0]); 18 | var ft:FileTree = new FileTree(file); 19 | WorkerSide.instance.sendMsg('update',ft); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/org/marz/spaceSniffer/worker/WorkerReady.as: -------------------------------------------------------------------------------- 1 | package org.marz.spaceSniffer.worker 2 | { 3 | import org.marz.sys.worker.MainSide; 4 | import org.puremvc.as3.interfaces.INotification; 5 | import org.puremvc.as3.patterns.command.SimpleCommand; 6 | 7 | public class WorkerReady extends SimpleCommand 8 | { 9 | public static const worker_side_ready:String = 'worker_side_ready'; 10 | 11 | override public function execute(notification:INotification):void 12 | { 13 | MainSide.instance.sendMsg('hi'); 14 | // MainSide.instance.sendMsg('launch_scan', '/Users/marzwu/Desktop'); 15 | } 16 | 17 | } 18 | } -------------------------------------------------------------------------------- /src/org/marz/sys/Init.as: -------------------------------------------------------------------------------- 1 | package org.marz.sys { 2 | import flash.events.Event; 3 | 4 | import org.puremvc.as3.interfaces.INotification; 5 | import org.puremvc.as3.patterns.command.SimpleCommand; 6 | 7 | public class Init extends SimpleCommand { 8 | public static const INIT:String = 'INIT'; 9 | 10 | override public function execute(notification:INotification):void { 11 | Global.stage.addEventListener(Event.ENTER_FRAME, OnEnterFrameHandler); 12 | } 13 | 14 | protected function OnEnterFrameHandler(event:Event):void { 15 | sendNotification(CmdSys.ENTER_FRAME); 16 | } 17 | 18 | } 19 | } -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | SpaceSniffer 4 | 5 | 6 | 7 | 8 | 9 | com.adobe.flexbuilder.project.flexbuilder 10 | 11 | 12 | 13 | 14 | com.adobe.flexbuilder.project.apollobuilder 15 | 16 | 17 | 18 | 19 | 20 | com.adobe.flexbuilder.project.apollonature 21 | com.adobe.flexbuilder.project.actionscriptnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/org/marz/spaceSniffer/m/GridsProxy.as: -------------------------------------------------------------------------------- 1 | package org.marz.spaceSniffer.m 2 | { 3 | import org.puremvc.as3.patterns.facade.Facade; 4 | import org.puremvc.as3.patterns.proxy.Proxy; 5 | import org.marz.spaceSniffer.m.vo.FileTree; 6 | 7 | public class GridsProxy extends Proxy 8 | { 9 | private static const NAME:String = 'GirdsProxy'; 10 | public var fileTree:FileTree; 11 | public var fileTreeArr:Array; 12 | public var dataChanged:Boolean; 13 | public function GridsProxy() 14 | { 15 | super(NAME, null); 16 | } 17 | 18 | public static function get instance():GridsProxy 19 | { 20 | return GridsProxy(Facade.getInstance().retrieveProxy(NAME)); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/org/marz/sys/OnEnterFrame.as: -------------------------------------------------------------------------------- 1 | package org.marz.sys { 2 | import org.puremvc.as3.interfaces.INotification; 3 | import org.puremvc.as3.patterns.command.SimpleCommand; 4 | 5 | public class OnEnterFrame extends SimpleCommand { 6 | override public function execute(notification:INotification):void { 7 | for each (var i:Function in funcs) { 8 | i(); 9 | } 10 | } 11 | 12 | private static var funcs:Object = {}; 13 | 14 | public static function addFunc(key:String, func:Function):void { 15 | funcs[key] = func; 16 | } 17 | 18 | public function deleteFunc(key:String):void { 19 | delete funcs[key]; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/SpaceSniffer.as: -------------------------------------------------------------------------------- 1 | package { 2 | import flash.display.Sprite; 3 | 4 | import org.puremvc.as3.patterns.facade.Facade; 5 | 6 | [SWF(width = '800', height = "600")] 7 | public class SpaceSniffer extends Sprite { 8 | public function SpaceSniffer() { 9 | // if(Worker.current.isPrimordial){ 10 | initMVC(); 11 | // MainSide.instance.init(loaderInfo); 12 | // MainSide.instance.start(); 13 | // }else{ 14 | // stage.frameRate = 2; 15 | // WorkerSide.instance.init(); 16 | // WorkerSide.instance.startWorking(); 17 | // } 18 | } 19 | 20 | private function initMVC():void { 21 | Facade.getInstance().registerCommand(Startup.STARTUP, Startup); 22 | 23 | Facade.getInstance().registerProxy(new StartupProxy); 24 | 25 | Facade.getInstance().sendNotification(Startup.STARTUP, stage); 26 | } 27 | 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/org/marz/spaceSniffer/c/InitWorkSpaceUI.as: -------------------------------------------------------------------------------- 1 | package org.marz.spaceSniffer.c { 2 | import flash.events.MouseEvent; 3 | 4 | import org.puremvc.as3.interfaces.INotification; 5 | import org.puremvc.as3.patterns.command.SimpleCommand; 6 | 7 | import shinater.swing.Menu; 8 | import shinater.swing.MenuBar; 9 | import shinater.swing.MenuItem; 10 | 11 | public class InitWorkSpaceUI extends SimpleCommand { 12 | public static const INIT_WORK_SPACE_UI:String = 'InitWorkSpaceUI'; 13 | 14 | override public function execute(notification:INotification):void { 15 | var pickMenu:Menu = new Menu; 16 | 17 | var pickMenuItem:MenuItem = new MenuItem('Pick Volume'); 18 | pickMenuItem.addEventListener(MouseEvent.CLICK, onChange); 19 | pickMenu.addMenuItem(pickMenuItem); 20 | 21 | var menuBar:MenuBar = new MenuBar; 22 | menuBar.addMenu(pickMenu); 23 | 24 | Global.stage.addChild(menuBar); 25 | 26 | function onChange(event:MouseEvent):void 27 | { 28 | var label:String = MenuItem(event.target).getLabel(); 29 | switch(label) 30 | { 31 | case 'Pick Volume': 32 | 33 | break; 34 | default: 35 | break; 36 | } 37 | } 38 | } 39 | 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/org/marz/spaceSniffer/c/ExploreFileTree.as: -------------------------------------------------------------------------------- 1 | package org.marz.spaceSniffer.c { 2 | import flash.utils.getTimer; 3 | 4 | import org.marz.spaceSniffer.m.vo.FileTree; 5 | import org.marz.spaceSniffer.m.GridsProxy; 6 | import org.puremvc.as3.interfaces.INotification; 7 | import org.puremvc.as3.patterns.command.SimpleCommand; 8 | 9 | public class ExploreFileTree extends SimpleCommand { 10 | public static const EXLORE_FILE_TREE:String = 'exlore_file_tree'; 11 | 12 | override public function execute(notification:INotification):void { 13 | var start:int = getTimer(); 14 | var end:Number = start + 30; 15 | 16 | var arr:Array = GridsProxy.instance.fileTreeArr; 17 | if (arr.length > 0) { 18 | GridsProxy.instance.dataChanged = true; 19 | var count:int = 0; 20 | while (arr.length) { 21 | // var shiftStart:int = getTimer(); 22 | var ft:FileTree = arr.shift(); 23 | // trace('shift time:', getTimer() - shiftStart); 24 | 25 | // var shiftStart:int = getTimer(); 26 | var directories:Array = ft.getDirectories(); 27 | // trace('getDirectories time:', getTimer() - shiftStart); 28 | 29 | if (ft.file.isDirectory && ft.explored != ft.numDirectories) { 30 | // var shiftStart:int = getTimer(); 31 | arr = arr.concat(directories); 32 | // trace('concat time:', getTimer() - shiftStart); 33 | } 34 | 35 | // if (count > 5) { 36 | // count = 0; 37 | if (end < getTimer()) { 38 | GridsProxy.instance.fileTreeArr = arr; 39 | trace('elapse time:', getTimer() - start, 'queue length', arr.length); 40 | break; 41 | } 42 | // } 43 | count++; 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/org/marz/sys/worker/WorkerSide.as: -------------------------------------------------------------------------------- 1 | package org.marz.sys.worker { 2 | import flash.events.Event; 3 | import flash.system.MessageChannel; 4 | import flash.system.Worker; 5 | 6 | import org.marz.spaceSniffer.worker.LaunchScan; 7 | 8 | public class WorkerSide { 9 | private var mainToBack:MessageChannel; 10 | 11 | private var backToMain:MessageChannel; 12 | 13 | public function WorkerSide() { 14 | } 15 | 16 | private static var _instance:WorkerSide; 17 | 18 | private var processors:Object; 19 | 20 | public static function get instance():WorkerSide { 21 | if (_instance == null) 22 | _instance = new WorkerSide; 23 | return _instance; 24 | } 25 | 26 | public function init():void { 27 | var worker:Worker = Worker.current; 28 | 29 | //Listen on mainToBack for SHARPEN events 30 | mainToBack = worker.getSharedProperty("mainToBack"); 31 | mainToBack.addEventListener(Event.CHANNEL_MESSAGE, onMainToBack); 32 | //Use backToMain to dispatch SHARPEN_COMPLETE 33 | backToMain = worker.getSharedProperty("backToMain"); 34 | } 35 | 36 | public function startWorking():void { 37 | processors = {}; 38 | processors['launch_scan'] = LaunchScan.launch; 39 | backToMain.send('worker_side_ready'); 40 | } 41 | 42 | protected function onMainToBack(event:Event):void { 43 | if (mainToBack.messageAvailable) { 44 | //Get the message type. 45 | var msg:*; 46 | var args:Array = []; 47 | while (msg = mainToBack.receive()) 48 | args.push(msg); 49 | trace(args); 50 | 51 | parse(args); 52 | } 53 | } 54 | 55 | private function parse(args:Array):void { 56 | var func:Function = processors[args.shift()]; 57 | if (func != null) 58 | func(args); 59 | } 60 | 61 | public function sendMsg(... args):void { 62 | while (args.length) 63 | backToMain.send(args.shift()); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/org/marz/spaceSniffer/v/PickVolumeMediator.as: -------------------------------------------------------------------------------- 1 | package org.marz.spaceSniffer.v { 2 | import flash.events.MouseEvent; 3 | import flash.filesystem.File; 4 | 5 | import org.bellona.utils.UIUtils; 6 | import org.marz.spaceSniffer.m.vo.FileTree; 7 | import org.puremvc.as3.interfaces.INotification; 8 | import org.puremvc.as3.patterns.mediator.Mediator; 9 | 10 | import shinater.swing.Button; 11 | import shinater.swing.List; 12 | import shinater.swing.Panel; 13 | import shinater.swing.Window; 14 | 15 | public class PickVolumeMediator extends Mediator { 16 | private static const NAME:String = 'PickVolumeMediator'; 17 | 18 | public static const SHOW_VOLUMES:String = 'showVolumes'; 19 | public static const PICK_A_VOLUME:String = 'pickAVolume'; 20 | 21 | public function PickVolumeMediator(viewComponent:Object = null) { 22 | super(NAME, viewComponent); 23 | } 24 | 25 | override public function listNotificationInterests():Array { 26 | return [SHOW_VOLUMES, PICK_A_VOLUME]; 27 | } 28 | 29 | override public function handleNotification(notification:INotification):void { 30 | switch (notification.getName()) { 31 | case PICK_A_VOLUME: 32 | 33 | break; 34 | case SHOW_VOLUMES: 35 | window.setTitle('选择一个磁盘'); 36 | 37 | 38 | var panel:Panel = window.getContent(); 39 | panel.removeChildren(); 40 | 41 | var lst:List = new List; 42 | lst.setSize(120, 150); 43 | panel.addChild(lst); 44 | 45 | var okBtn:Button = new Button('确定'); 46 | okBtn.x = 160; 47 | okBtn.addEventListener(MouseEvent.CLICK, function onOkBtn(event:MouseEvent):void { 48 | var volume:String = String(lst.getSelectedItem()); 49 | if (volume) { 50 | var file:File = new File(volume); 51 | sendNotification(GridsMediator.SHOW, new FileTree(file)); 52 | UIUtils.removeFromParent(window); 53 | } 54 | }); 55 | panel.addChild(okBtn); 56 | 57 | for each (var i:File in notification.getBody()) { 58 | lst.addItem(i.name); 59 | } 60 | 61 | window.closeButton.visible = false; 62 | window.setResizable(false); 63 | window.setModal(true); 64 | window.setVisible(true); 65 | Global.stage.addChild(window); 66 | UIUtils.centerToStage(window, window.stage); 67 | break; 68 | default: 69 | break; 70 | } 71 | } 72 | 73 | 74 | private function get window():Window { 75 | return Window(viewComponent); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/org/marz/sys/worker/MainSide.as: -------------------------------------------------------------------------------- 1 | package org.marz.sys.worker { 2 | import flash.display.LoaderInfo; 3 | import flash.events.Event; 4 | import flash.system.MessageChannel; 5 | import flash.system.Worker; 6 | import flash.system.WorkerDomain; 7 | 8 | import org.marz.spaceSniffer.worker.LaunchScan; 9 | import org.puremvc.as3.patterns.facade.Facade; 10 | 11 | public class MainSide { 12 | private var loaderInfo:LoaderInfo; 13 | 14 | private var worker:Worker; 15 | 16 | private var mainToBack:MessageChannel; 17 | 18 | private var backToMain:MessageChannel; 19 | 20 | 21 | public function MainSide() { 22 | 23 | } 24 | 25 | public function init(loaderInfo:LoaderInfo):void { 26 | this.loaderInfo = loaderInfo; 27 | } 28 | 29 | public function start():void { 30 | worker = WorkerDomain.current.createWorker(loaderInfo.bytes); //WorkerFactory.getWorkerFromClass(SharpenWorker, loaderInfo.bytes); 31 | 32 | //Create message channel TO the worker 33 | mainToBack = Worker.current.createMessageChannel(worker); 34 | 35 | //Create message channel FROM the worker, add a listener. 36 | backToMain = worker.createMessageChannel(Worker.current); 37 | backToMain.addEventListener(Event.CHANNEL_MESSAGE, onBackToMain, false, 0, true); 38 | 39 | //Now that we have our two channels, inject them into the worker as shared properties. 40 | //This way, the worker can see them on the other side. 41 | worker.setSharedProperty("backToMain", backToMain); 42 | worker.setSharedProperty("mainToBack", mainToBack); 43 | 44 | //Lastly, start the worker. 45 | worker.start(); 46 | } 47 | 48 | protected function onBackToMain(event:Event):void { 49 | var msg:*; 50 | var args:Array = []; 51 | while(msg = backToMain.receive()) 52 | args.push(msg); 53 | trace(args); 54 | 55 | Facade.getInstance().sendNotification(args.shift(), args); 56 | } 57 | 58 | private static var _instance:MainSide; 59 | 60 | public static function get instance():MainSide { 61 | if (_instance == null) 62 | _instance = new MainSide; 63 | return _instance; 64 | } 65 | 66 | public function sendMsg(...args):void 67 | { 68 | while(args.length) 69 | mainToBack.send(args.shift()); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /src/org/marz/spaceSniffer/v/GridsMediator.as: -------------------------------------------------------------------------------- 1 | package org.marz.spaceSniffer.v { 2 | import flash.geom.Rectangle; 3 | 4 | import org.marz.spaceSniffer.c.ExploreFileTree; 5 | import org.marz.spaceSniffer.c.Refresh; 6 | import org.marz.sys.OnEnterFrame; 7 | import org.puremvc.as3.interfaces.INotification; 8 | import org.puremvc.as3.patterns.facade.Facade; 9 | import org.puremvc.as3.patterns.mediator.Mediator; 10 | import org.marz.spaceSniffer.m.vo.FileTree; 11 | import org.marz.spaceSniffer.m.GridsProxy; 12 | import org.marz.spaceSniffer.v.vo.GridRenderer; 13 | 14 | public class GridsMediator extends Mediator { 15 | private static const NAME:String = 'Grids'; 16 | 17 | public static const SHOW:String = 'show'; 18 | 19 | public static const UPDATE:String = 'update'; 20 | 21 | private var count:int; 22 | 23 | public function GridsMediator() { 24 | super(NAME, null); 25 | 26 | facade.registerProxy(new GridsProxy); 27 | OnEnterFrame.addFunc('refresh', Refresh.doRefresh); 28 | } 29 | 30 | override public function handleNotification(notification:INotification):void { 31 | switch (notification.getName()) { 32 | case SHOW: 33 | GridsProxy.instance.fileTree = notification.getBody() as FileTree; 34 | GridsProxy.instance.fileTreeArr = GridsProxy.instance.fileTree.getDirectories(); 35 | dataChanged(GridsProxy.instance.fileTree); 36 | sendNotification(ExploreFileTree.EXLORE_FILE_TREE); 37 | break; 38 | case UPDATE: 39 | if (GridsProxy.instance.fileTree) { 40 | if (GridsProxy.instance.dataChanged) { 41 | if (count == 24) { 42 | count = 0; 43 | dataChanged(GridsProxy.instance.fileTree); 44 | GridsProxy.instance.dataChanged = false; 45 | } 46 | count++; 47 | } 48 | sendNotification(ExploreFileTree.EXLORE_FILE_TREE); 49 | } 50 | default: 51 | break; 52 | } 53 | } 54 | 55 | private function dataChanged(ft:FileTree):void { 56 | Global.stage.removeChildren(); 57 | 58 | var gridRenderer:GridRenderer = new GridRenderer; 59 | Global.stage.addChild(gridRenderer); 60 | var rect:Rectangle = new Rectangle(0, 0, Global.stage.stageWidth, Global.stage.stageHeight); 61 | gridRenderer.depth = 0; 62 | gridRenderer.update(ft, rect); 63 | } 64 | 65 | override public function listNotificationInterests():Array { 66 | return [SHOW, UPDATE]; 67 | } 68 | 69 | public static function get instance():GridsMediator { 70 | return GridsMediator(Facade.getInstance().retrieveMediator(NAME)); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Startup.as: -------------------------------------------------------------------------------- 1 | package { 2 | import flash.display.Stage; 3 | import flash.events.Event; 4 | import flash.events.MouseEvent; 5 | import flash.filesystem.File; 6 | import flash.system.Capabilities; 7 | 8 | import org.marz.spaceSniffer.c.ExploreFileTree; 9 | import org.marz.spaceSniffer.c.InitWorkSpaceUI; 10 | import org.marz.spaceSniffer.m.vo.FileTree; 11 | import org.marz.spaceSniffer.v.GridsMediator; 12 | import org.marz.spaceSniffer.v.PickVolumeMediator; 13 | import org.marz.sys.CmdSys; 14 | import org.marz.sys.Init; 15 | import org.marz.sys.OnEnterFrame; 16 | import org.puremvc.as3.interfaces.INotification; 17 | import org.puremvc.as3.patterns.command.SimpleCommand; 18 | 19 | import shinater.swing.Menu; 20 | import shinater.swing.MenuBar; 21 | import shinater.swing.MenuItem; 22 | import shinater.swing.Window; 23 | 24 | public class Startup extends SimpleCommand { 25 | public static const STARTUP:String = 'startup'; 26 | 27 | override public function execute(notification:INotification):void { 28 | var stage:Stage = notification.getBody() as Stage; 29 | Global.stage = stage; 30 | Global.stage = stage; 31 | 32 | initMVC(); 33 | 34 | sendNotification(Init.INIT); 35 | sendNotification(InitWorkSpaceUI.INIT_WORK_SPACE_UI); 36 | 37 | var directories:Array = File.getRootDirectories(); 38 | // sendNotification(Grids.SHOW, new FileTree(directories[0])); 39 | 40 | if (Capabilities.os.indexOf('Mac') > -1) 41 | var path:String = '/Users/marzwu/'; //Desktop Downloads 42 | else if (Capabilities.os.indexOf('Win') > -1) { 43 | // path = 'E:/klive/dirty/snatchly'; 44 | // path = 'E:/klive/'; 45 | path = 'E:/'; 46 | sendNotification(PickVolumeMediator.SHOW_VOLUMES, directories); 47 | } else { 48 | path = '/'; 49 | } 50 | 51 | // var file:File = new File(path); 52 | // sendNotification(GridsMediator.SHOW, new FileTree(file)); 53 | } 54 | 55 | private function onChange(event:Event):void 56 | { 57 | trace(event); 58 | var getLabel:String = MenuItem(event.target).getLabel(); 59 | } 60 | 61 | private function initMVC():void { 62 | facade.registerCommand(CmdSys.ENTER_FRAME, OnEnterFrame); 63 | // facade.registerCommand(WorkerReady.worker_side_ready, WorkerReady); 64 | facade.registerCommand(ExploreFileTree.EXLORE_FILE_TREE, ExploreFileTree); 65 | facade.registerCommand(Init.INIT, Init); 66 | facade.registerCommand(InitWorkSpaceUI.INIT_WORK_SPACE_UI, InitWorkSpaceUI); 67 | 68 | facade.registerMediator(new GridsMediator); 69 | facade.registerMediator(new PickVolumeMediator(new Window)); 70 | } 71 | 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /.actionScriptProperties: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /src/org/marz/spaceSniffer/m/vo/FileTree.as: -------------------------------------------------------------------------------- 1 | package org.marz.spaceSniffer.m.vo { 2 | import flash.events.FileListEvent; 3 | import flash.filesystem.File; 4 | import flash.geom.Rectangle; 5 | import flash.utils.getTimer; 6 | import org.marz.spaceSniffer.v.vo.GridRenderer; 7 | 8 | public class FileTree { 9 | public var file:File; 10 | 11 | public function FileTree(file:File) { 12 | this.file = file; 13 | if (file.isDirectory == false) { 14 | try { 15 | addSize(file.size); 16 | } catch (e:Error) { 17 | trace(e.message); 18 | } 19 | } 20 | } 21 | 22 | public var parent:FileTree; 23 | 24 | private var children:Array; 25 | 26 | private var _size:Number = 0; 27 | 28 | public var deep:int; 29 | public var numDirectories:uint; 30 | public var explored:int; 31 | 32 | private var directories:Array; 33 | 34 | public function get size():Number { 35 | return _size; 36 | } 37 | 38 | public function addSize(s:Number):Number { 39 | _size += s; 40 | sort(); 41 | if (parent) 42 | parent.addSize(s); 43 | // trace('size:'+size); 44 | return size; 45 | } 46 | 47 | public function getDirectoryListing():Array { 48 | if (children) 49 | return children; 50 | 51 | if (file.isDirectory == false) 52 | return null; 53 | 54 | children = []; 55 | 56 | var sync:Boolean = true; 57 | 58 | if (sync) { 59 | // var s:int = getTimer(); 60 | var list:Array = file.getDirectoryListing(); 61 | // trace('getDirectoryListing time', getTimer() - s); 62 | 63 | var dSize:Number = parseList(list, children); 64 | addSize(dSize); 65 | sort(); 66 | } else { 67 | file.getDirectoryListingAsync(); 68 | file.addEventListener(FileListEvent.DIRECTORY_LISTING, directoryListingHandler); 69 | 70 | function directoryListingHandler(event:FileListEvent):void { 71 | var list:Array = event.files; 72 | parseList(list, children); 73 | } 74 | } 75 | 76 | return children; 77 | } 78 | 79 | private function parseList(list:Array, children:Array):Number { 80 | var r:Number = 0; 81 | for each (var i:File in list) { 82 | var ft:FileTree = new FileTree(i); 83 | ft.deep = deep + 1; 84 | ft.parent = this; 85 | children.push(ft); 86 | r += ft.size; 87 | } 88 | return r; 89 | } 90 | 91 | 92 | public function sort():void { 93 | var children:Array = getDirectoryListing(); 94 | if (children) { 95 | // var s:int = getTimer(); 96 | children.sortOn('size', Array.NUMERIC | Array.DESCENDING); 97 | // trace('sort time', getTimer() - s); 98 | } 99 | } 100 | 101 | public function getDirectories():Array { 102 | if (directories) 103 | return directories.concat(); 104 | 105 | directories = []; 106 | for each (var i:FileTree in getDirectoryListing()) { 107 | if (i.file.isDirectory) 108 | directories.push(i); 109 | } 110 | numDirectories = directories.length; 111 | 112 | if (numDirectories == 0 && parent) 113 | parent.explored++; 114 | return directories; 115 | } 116 | 117 | public function group(renderer:GridRenderer, rect:Rectangle, children:Array, size:Number):void { 118 | var area:Number = rect.width * rect.height; 119 | 120 | var horizal:Boolean = rect.width > rect.height; 121 | var minArea:Number 122 | if (horizal) 123 | minArea = rect.height * rect.height * 0.618; 124 | else 125 | minArea = rect.width * rect.width * 0.618; 126 | 127 | var per:Number = minArea / area; 128 | 129 | var sum:Number = 0; 130 | var interval:Array = []; 131 | var w:Number = rect.width; 132 | var h:Number = rect.height; 133 | 134 | while (children.length) { 135 | var i:FileTree = children.shift(); 136 | sum += i.size; 137 | interval.push(i); 138 | 139 | 140 | var dPer:Number = sum / size; 141 | if (dPer >= per) { 142 | var curr:Rectangle = rect.clone(); 143 | if (horizal) { 144 | w = int(dPer * area / h); 145 | curr.width = w; 146 | 147 | rect.x += w; 148 | rect.width -= w; 149 | } else { 150 | h = int(dPer * area / w); 151 | curr.height = h; 152 | 153 | rect.y += h; 154 | rect.height -= h; 155 | } 156 | 157 | if (dPer < 1) 158 | group(renderer, curr, interval, sum); 159 | else { 160 | // renderer.graphics.lineStyle(1); 161 | 162 | renderGroup(renderer, interval, sum, curr.x, curr.y, curr.width, curr.height); 163 | 164 | // if (interval.length == 1) { 165 | //// renderer.graphics.drawRect(curr.x, curr.y, curr.width, curr.height); 166 | // render(renderer, interval[0], curr.x, curr.y, curr.width, curr.height); 167 | // } else { 168 | // var dHorizal:Boolean = curr.width > curr.height; 169 | // var dd:int; 170 | // if (dHorizal) { 171 | // dd = curr.width * interval[0].size / sum; 172 | //// renderer.graphics.drawRect(curr.x, curr.y, dd, curr.height); 173 | //// renderer.graphics.drawRect(curr.x + dd, curr.y, curr.width - dd, curr.height); 174 | // render(renderer, interval[0], curr.x, curr.y, dd, curr.height); 175 | // render(renderer, interval[1], curr.x + dd, curr.y, curr.width - dd, curr.height); 176 | // } else { 177 | // dd = curr.height * interval[0].size / sum; 178 | //// renderer.graphics.drawRect(curr.x, curr.y, curr.width, dd); 179 | //// renderer.graphics.drawRect(curr.x, curr.y + dd, curr.width, curr.height - dd); 180 | // render(renderer, interval[0], curr.x, curr.y, curr.width, dd); 181 | // render(renderer, interval[1], curr.x, curr.y + dd, curr.width, curr.height - dd); 182 | // } 183 | // } 184 | } 185 | 186 | group(renderer, rect.clone(), children, size - sum); 187 | break; 188 | } 189 | } 190 | } 191 | 192 | private function renderGroup(renderer:GridRenderer, interval:Array, sum:Number, x:Number, y:Number, width:Number, height:Number):void { 193 | var dHorizal:Boolean = width > height; 194 | var dd:int; 195 | var cursor:Number = 0; 196 | for each (var i:FileTree in interval) { 197 | var scale:Number = cursor / sum; 198 | if (dHorizal) { 199 | dd = width * scale; 200 | render(renderer, i, x + dd, y, width * i.size / sum, height); 201 | } else { 202 | dd = height * scale; 203 | render(renderer, i, x, y + dd, width, height * i.size / sum); 204 | } 205 | cursor += i.size; 206 | } 207 | } 208 | 209 | private function render(renderer:GridRenderer, f:FileTree, x:Number, y:Number, width:Number, height:Number):void { 210 | var r:GridRenderer = new GridRenderer; 211 | r.x = x; 212 | r.y = y; 213 | r.depth = renderer.depth + 1; 214 | r.update(f, new Rectangle(0, 0, width, height)); 215 | renderer.addChild(r); 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/org/marz/spaceSniffer/v/vo/GridRenderer.as: -------------------------------------------------------------------------------- 1 | package org.marz.spaceSniffer.v.vo { 2 | import flash.display.Sprite; 3 | import flash.events.ContextMenuEvent; 4 | import flash.events.MouseEvent; 5 | import flash.geom.Rectangle; 6 | import flash.ui.ContextMenu; 7 | import flash.ui.ContextMenuItem; 8 | 9 | import org.puremvc.as3.patterns.facade.Facade; 10 | 11 | import shinater.swing.Label; 12 | import org.marz.spaceSniffer.m.vo.FileTree; 13 | import org.marz.spaceSniffer.v.GridsMediator; 14 | 15 | public class GridRenderer extends Sprite { 16 | private static const min_size:int = 5; 17 | 18 | private static const LABEL_HEIGHT:Number = 20; 19 | 20 | private static const UNIT_ARR:Array = new Array("Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"); 21 | 22 | private var label:Label; 23 | 24 | public function GridRenderer() { 25 | super(); 26 | label = new Label('path 0'); 27 | 28 | this.doubleClickEnabled = true; 29 | 30 | // addEventListener(MouseEvent.CLICK, onClick); 31 | addEventListener(MouseEvent.DOUBLE_CLICK, onClick); 32 | // addEventListener(MouseEvent.RIGHT_CLICK, onClick); 33 | 34 | var menu:ContextMenu = new ContextMenu; 35 | this.contextMenu = menu; 36 | 37 | var item:ContextMenuItem; 38 | item = new ContextMenuItem('parent'); 39 | item.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onMenuItemSelected); 40 | menu.items.push(item); 41 | item = new ContextMenuItem('open'); 42 | item.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onMenuItemSelected); 43 | menu.items.push(item); 44 | item = new ContextMenuItem('delete'); 45 | item.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onMenuItemSelected); 46 | menu.items.push(item); 47 | } 48 | 49 | protected function onMenuItemSelected(event:ContextMenuEvent):void { 50 | switch (event.target.caption) { 51 | case 'parent': 52 | if (fileTree.parent) { 53 | Facade.getInstance().sendNotification(GridsMediator.SHOW, fileTree.parent); 54 | } 55 | break; 56 | case 'open': 57 | try{ 58 | fileTree.file.openWithDefaultApplication(); 59 | }catch(e:Error){ 60 | trace(e); 61 | } 62 | break; 63 | case 'delete': 64 | if (fileTree.file.isDirectory) 65 | fileTree.file.deleteDirectory(true); 66 | else 67 | fileTree.file.deleteFile(); 68 | break; 69 | } 70 | } 71 | 72 | protected function onClick(event:MouseEvent):void { 73 | switch (event.type) { 74 | case MouseEvent.CLICK: 75 | break; 76 | case MouseEvent.DOUBLE_CLICK: 77 | Facade.getInstance().sendNotification(GridsMediator.SHOW, fileTree); 78 | break; 79 | case MouseEvent.RIGHT_CLICK: 80 | break; 81 | } 82 | event.stopImmediatePropagation(); 83 | } 84 | 85 | public function update(fileTree:FileTree, rect:Rectangle):void { 86 | this.fileTree = fileTree; 87 | 88 | if (depth > 2) 89 | return; 90 | 91 | // if (rect.width < min_size || rect.height < min_size) 92 | // return; 93 | 94 | graphics.clear(); 95 | graphics.lineStyle(1); 96 | if (fileTree.file.isDirectory) 97 | graphics.beginFill(0x008888, .8); 98 | else 99 | graphics.beginFill(0xffffff, .8); 100 | 101 | graphics.drawRect(0, 0, rect.width, rect.height); 102 | graphics.endFill(); 103 | 104 | var name:String = fileTree.file.nativePath; 105 | name = name.substr(name.lastIndexOf('/') + 1); 106 | name = name.substr(name.lastIndexOf('\\') + 1); 107 | label.setAutoSize('left'); 108 | 109 | var size:Number = fileTree.size; 110 | var _index:int; 111 | var sizeStr:String = (size / Math.pow(1024, (_index = int(Math.log(size) / Math.log(1024))))).toPrecision(3) + UNIT_ARR[_index]; 112 | if (fileTree.file.isDirectory) 113 | label.setText(name + ': ' + sizeStr); 114 | else 115 | label.setText(name + '\n' + sizeStr); 116 | 117 | if (rect.width < label.width) 118 | label.setText(sizeStr + ''); 119 | 120 | if (rect.width >= label.width && rect.height >= label.height) { 121 | addChild(label); 122 | 123 | if (false == fileTree.file.isDirectory) { 124 | label.x = (width - label.width) >> 1; 125 | label.y = (height - label.height) >> 1; 126 | } 127 | } 128 | 129 | horizal = rect.width > rect.height; 130 | 131 | if (fileTree.file.isDirectory) { 132 | var list:Array = fileTree.getDirectoryListing(); 133 | 134 | var clientW:Number = rect.width - min_size * 2; 135 | var clientH:Number = rect.height - LABEL_HEIGHT - min_size; 136 | 137 | var area:int = clientW * clientH; 138 | 139 | var acturalW:Number = clientW; 140 | var acturalH:Number = clientH; 141 | var cursorX:int = min_size; 142 | var cursorY:int = LABEL_HEIGHT; 143 | 144 | if (clientW < 1 || clientH < 1) 145 | return; 146 | 147 | fileTree.group(this, new Rectangle(cursorX, cursorY, acturalW, acturalH), fileTree.getDirectoryListing().concat(), size); 148 | return; 149 | 150 | for each (var i:FileTree in list) { 151 | var renderer:GridRenderer = new GridRenderer; 152 | renderer.depth = depth + 1; 153 | 154 | horizal = acturalW > acturalH; 155 | 156 | if (horizal) { 157 | renderer.x = cursorX; 158 | renderer.y = cursorY; 159 | 160 | var h:Number = acturalH; 161 | var w:int = area * (i.size / size) / h; 162 | renderer.update(i, new Rectangle(0, 0, Math.max(1, w), Math.max(1, h))); 163 | 164 | cursorX += w; 165 | acturalW -= w; 166 | } else { 167 | renderer.x = cursorX; 168 | renderer.y = cursorY; 169 | 170 | w = acturalW; 171 | h = area * (i.size / size) / w; 172 | 173 | renderer.update(i, new Rectangle(0, 0, Math.max(1, w), Math.max(1, h))); 174 | 175 | cursorY += h; 176 | acturalH -= h; 177 | } 178 | addChild(renderer); 179 | } 180 | } 181 | } 182 | 183 | private var _depth:int; 184 | 185 | public function get depth():int { 186 | return _depth; 187 | } 188 | 189 | public function set depth(value:int):void { 190 | if (_depth == value) 191 | return; 192 | _depth = value; 193 | } 194 | 195 | public var horizal:Boolean; 196 | 197 | public var fileTree:FileTree; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/SpaceSniffer-app.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | 18 | SpaceSniffer 19 | 20 | 21 | SpaceSniffer 22 | 23 | 25 | SpaceSnifferAnywhere 26 | 27 | 30 | 1.0.0 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | [This value will be overwritten by Flash Builder in the output app.xml] 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 | false 113 | false 114 | true 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 136 | 153 | 154 | 157 | 158 | 159 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 208 | 209 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | --------------------------------------------------------------------------------