Schemaphic Systems Blog

Sharing experiences in Flash, Flex and AIR

Archive for the ‘AIR’ Category

Global TImer in ActionScript

leave a comment »

With my experience with RIA using actionscript, I have come most applications where multiple timers are required.
As the application grows complex, the more and more timers added does slow up the application performance to lot.

That is where I thought of developing a utility class called GlobalTimer. It is a singleton class and runs only a single timer. So where ever in your application a timer is necessary, just add a timer name to this global timer with other parameters and you are done without hitting the application performance.

This class is a pure actionscript class and hence can be used both for flash, flex and AIR projects.

GlobalTimer.as

package com.te.utilities
{
import flash.events.EventDispatcher;
import flash.events.TimerEvent;
import flash.utils.Dictionary;
import flash.utils.Timer;

public class GlobalTimer extends EventDispatcher
{
public static const EQUALS : String = "equals";
public static const DIFFERENCE_FROM_CURRENT_TIME : String = "differs";
public static const CALL_IN_INTERVALS : String = "intervals";

public static var TIME_INTERVAL : int = 100;
public static var instance : GlobalTimer;

private var timer:Timer;
private var currentDate:Date;
private var currentTime:int;//in milliseconds
private var _running:Boolean = false;

private var timersForCheck:Dictionary;

public function GlobalTimer( enf:SingletonEnforcer )
{
timersForCheck = new Dictionary();

super();
}

public static function getInstance() : GlobalTimer
{
if( instance == null ) instance = new GlobalTimer( new SingletonEnforcer() );
return instance;
}

public function start() : void
{
if( _running )    return;

timer = new Timer( TIME_INTERVAL );
timer.addEventListener(TimerEvent.TIMER, onTimerHandler, false, 0, true );
timer.start();

_running = true;
}

private function onTimerHandler( event:TimerEvent ) : void
{
currentDate = new Date();
currentTime = ( currentDate.getHours() * 60 * 60 ) + ( currentDate.getMinutes() * 60 ) + ( currentDate.getSeconds() );

for each( var prop:* in timersForCheck ){
if( prop != null ){
switch( prop[2] ){
case EQUALS:
if( currentTime == ( prop[0] + prop[1] ) ){
//AUTO UPDATE CHECK
prop[3][ String( prop[4] ) ]();
}
break;

case DIFFERENCE_FROM_CURRENT_TIME:
//IDLE TIME CHECK
if( prop[5] != null ){
prop[3][ String( prop[5] ) ]();
}
if( ( currentTime - prop[0] ) == prop[1] && prop[4] != null ){
prop[3][ String( prop[4] ) ]();
}
break;

default:
//CALL_IN_INTERVALS:
if( ( timer.currentCount - prop[0] ) == prop[1] && prop[5] != null ){
prop[0] = timer.currentCount;
prop[3][ String( prop[5] ) ]();
}
break;
}
}
}
}

public function addTimer( name:String, time:Number, check:String, object:*, functionOnComplete:String=null, functionOnTimer:String=null ) : void
{
//timersForCheck[name] = [   0,      1,    2,     3,            4,                 5        ];
timersForCheck[name] = [ timer.currentCount, time, check, object, functionOnComplete, functionOnTimer ];
}

public function removeTimer( name:String ) : void
{
timersForCheck[name] = null;
}

public function isTimerRunning( name:String ) : Boolean
{
var prop:* = timersForCheck[ name ];
if( prop == null ){
return false;
}
return true;
}

public function getTimerData( name:String ) : Object
{
var prop:* = timersForCheck[ name ];
if( prop == null ){
return null;
}
var data:Object = {};
data.currentTime = ( currentTime - prop[0] );
data.remainingTime = ( prop[1] - data.currentTime );
return data;
}

public function stop() : void
{
if( timer != null ){
timer.stop();
timer.reset();
timer.removeEventListener( TimerEvent.TIMER, onTimerHandler, false );
timer = null;

_running = false;

for each( var prop:* in timersForCheck ){
if( prop != null ){
prop = null;
}
}
timersForCheck = null;
timersForCheck = new Dictionary();
}
}

public function get running() : Boolean
{
return _running;
}

protected function reset():void
{
stop();
}
}
}
internal class SingletonEnforcer{}

In the application use the following code:

//Code to be used in your application
private var globalTimer:GlobalTimer;

globalTimer = GlobalTimer.getInstance();
if( !globalTimer.running ){
globalTimer.start();//starts timer
}

//checks if the timer is already running
if ( !globalTimer.isTimerRunning( "game_timer" ) ) {
globalTimer.addTimer( "game_timer", _asuraThrowWeaponInterval, GlobalTimer.CALL_IN_INTERVALS, this, null, "onIntervalEventHandler" );
}

globalTimer.removeTimer( "game_timer" );//removes/clears the particular timer
globalTimer.stop();//stops all the timers

Written by Deepanjan Das

November 22, 2011 at 1:22 PM

Clone an ArrayCollection

with 4 comments

Easy way to clone an ArrayCollection without interfering the current collection.

/*
@usage:
var myCollection:ArrayCollection = new ArrayCollection( [1, 2, 3, 4] );
var clonedCollection:ArrayCollection = clone( myCollection );

trace( myCollection.toString() ); // 1,2,3,4
trace( clonedCollection.toString() ); // 1,2,3,4

clonedCollection.removeItemAt(0);

trace( myCollection.toString() ); // 1,2,3,4
trace( clonedCollection.toString() ); // 2,3,4
*/

public function clone( value:ArrayCollection ) : ArrayCollection
{
    var newCollection:ArrayCollection = new ArrayCollection( value.toArray() );
    return newCollection;
}

Written by Deepanjan Das

September 16, 2010 at 8:24 AM

Writing & executing CMD scripts through AIR

leave a comment »

The following script writes a CMD file, executes it and disposes itself.

Here a cmd file named “hide.cmd” is getting created which sets the file attribute of test.txt to hidden and then deletes itseld (hide.cmd).

private var applicationDirectory:File;
public function createCMDFile():void
{
    applicationDirectory = File.desktopDirectory;
    var cmdFile:File = applicationDirectory.resolvePath( 'hide.cmd' );
    var stream:FileStream = new FileStream()
    stream.open( cmdFile, FileMode.WRITE );

    var dataString:String = "ATTRIB +H \" C:\My Documents\test.txt \"";

    stream.writeUTFBytes( dataString );
    stream.close();

    stream = null;

    var nativeProcessStartupInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo();
    nativeProcessStartupInfo.executable = cmdFile;

    var process:NativeProcess = new NativeProcess();
    process.start(nativeProcessStartupInfo);
    process.addEventListener( NativeProcessExitEvent.EXIT, onExitHandler );
}

private function onExitHandler( event:NativeProcessExitEvent ):void
{
    var cmdFile:File = applicationDirectory.resolvePath( 'hide.cmd' );
    cmdFile.deleteFile();
}

Please Remember to set <supportedProfiles>extendedDesktop</supportedProfiles> in air descriptor file. Check AIR NativeProcess compatible SDK before compiling.

Written by Deepanjan Das

September 10, 2010 at 3:52 PM

Posted in AIR, Code Snippets

Tagged with

AIR Application Updater

leave a comment »

Look for “<version>” tag in the Application-app.xml file which gets generated while creating a WindowedApplication. The value of this tag resembles the current version of the air.

import air.update.ApplicationUpdaterUI;
import air.update.events.UpdateEvent;
import air.update.events.StatusFileUpdateErrorEvent;

var applicationUpdater:ApplicationUpdaterUI;

/*
* Check to see if application update is required
*/
public function checkForApplicationUpdate() : void
{
applicationUpdater = new ApplicationUpdaterUI();
applicationUpdater.updateURL = “update.xml”;//sample update.xml is provided below
applicationUpdater.isCheckForUpdateVisible = false;
applicationUpdater.addEventListener( UpdateEvent.INITIALIZED, onUpdateInitHandler );
applicationUpdater.addEventListener( ErrorEvent.ERROR, onErrorHandler );
applicationUpdater.addEventListener( StatusFileUpdateErrorEvent.FILE_UPDATE_ERROR, onErrorHandler );
}

private function onUpdateInitHandler( event:UpdateEvent ) : void
{
/*checkNow API actually compares the version of the current
installed application from Application-app.xml
with the version from update.xml and acts accordingly.*/
applicationUpdater.checkNow();
}

private function onErrorHandler( event:Event ) : void
{
trace(“onErrorHandler”);
}

checkForApplicationUpdate();

/*************update.xml***************/

<?xml version=”1.0″ encoding=”utf-8″?>
<update xmlns=”http://ns.adobe.com/air/framework/update/description/1.0″&gt;
<version>v2</version>
<url>http://tourdeflex.adobe.com/blogfiles/AIRAutoUpdateSample/server/AIRAutoUpdateSample-v2.air</url&gt;
<description><![CDATA[
v2
* These notes are displayed to the user in the update dialog
* Typically, this is used to summarize what’s new in the release
]]></description>
</update>

Written by Deepanjan Das

July 20, 2010 at 12:26 PM

AIR application version check

with one comment

Look for “<version>” tag in the Application-app.xml file which gets generated while creating a WindowedApplication. The value of this tag resembles the current version of the air.

public function getAIRApplicationVersion() : String {
var applicationXML:XML = NativeApplication.nativeApplication.applicationDescriptor;
var ns:Namespace = applicationXML.namespace();
return applicationXML.ns::version;
}

trace( getAIRApplicationVersion() );

Written by Deepanjan Das

July 20, 2010 at 12:25 PM

Right Click Context Menu Option

leave a comment »

Hey! I was working on a project where I needed to use different ContextMenus on different objects. Hence to make my life easier, I developed a class for RightClickMenus. I would like to share it as this may help some one to speed up development.

I have not placed comments in the RightClickMenus class as the method API names are self-explanatory.

//import statement
import com.utils.RightClickMenus;

//Declare RightClickMenus Instance
//pass the object on which context menus needs tobe viewed
//pass a boolean to indicate whether you want to hide the buildInItems
var rtClickMenus:RightClickMenus = new RightClickMenus( this, false );

//Adding Custom menu Items
//pass menu names
//pass menu click funtion name if you want to add an handler
//pass a boolean value if you want a separator above this menu item
rtClickMenus.addMenuItem( “Menu 1”, onMenuCall_1 );
rtClickMenus.addMenuItem( “Developed by deepanjandas”, null, true );
rtClickMenus.addMenuItem( “Menu 2”, onMenuCall_2 );
rtClickMenus.addMenuItem( “© Deepanjan” );

//Add a separator at a particular position
rtClickMenus.addSeparatorAt( 3 );

//Remove a custom menu item from a particular position
//rtClickMenus.removeMenuItemAt( 4 );

//Remove a separator from a particular position
//rtClickMenus.removeSeparatorAt( 3 );

//Remove all custom menu items
//rtClickMenus.removeAllItems();

//ContentMenuItem select event handlers
function onMenuCall_1( event:Event ) {
trace( “onMenuCall_1 called” );
}
function onMenuCall_2( event:ContextMenuEvent ) {
trace( “onMenuCall_2 called” );
}

/**************** RightClickMenus.as ********************/

package com.utils
{
import flash.ui.ContextMenu;
import flash.ui.ContextMenuItem;
import flash.ui.ContextMenuBuiltInItems;
import flash.events.ContextMenuEvent;
import flash.system.System;

public class RightClickMenus
{
private var contectMenuObject:Object;
private var showBuildInItems:Boolean;
private var menuCollection:Array;
private var customContextMenu:ContextMenu;

public function RightClickMenus( object:Object, showBuildInItems:Boolean=false )
{
contectMenuObject = object;
menuCollection = [];
this.showBuildInItems = showBuildInItems;

customContextMenu = new ContextMenu();

if ( !showBuildInItems )
customContextMenu.hideBuiltInItems();
}

public function addMenuItemAt( position:int, _name:String, listener:Function=null, separator:Boolean=false ):void
{
var item:ContextMenuItem = new ContextMenuItem( _name, separator );
if( listener != null )
item.addEventListener( ContextMenuEvent.MENU_ITEM_SELECT, listener );

if ( position < 0 ) {
menuCollection.push( item );
} else {
var startArray:Array = menuCollection.slice( 0, position-1 );
var endArray:Array = menuCollection.slice( position );
menuCollection = [];
menuCollection.join( startArray );
menuCollection.push( item );
menuCollection.join( endArray );
}

buildCustomMenus();
}

public function addMenuItem( _name:String, listener:Function=null, separator:Boolean=false ):void
{
addMenuItemAt( -1, _name, listener, separator )
}

public function removeMenuItemAt( position:int ):void
{
menuCollection.splice( position – 1, 1 );

removeSeparatorAt( position );

buildCustomMenus();
}

public function removeAllItems():void
{
menuCollection = [];

buildCustomMenus();
}

public function disableMenuAt( position:int ):void
{
if ( position < 1 || position > menuCollection.length )
return;

var item:ContextMenuItem = menuCollection[( position – 1 )];
item.enabled = false;
}

public function enableMenuAt( position:int ):void
{
if ( position < 1 || position > menuCollection.length )
return;

var item:ContextMenuItem = menuCollection[( position – 1 )];
item.enabled = true;
}

public function removeSeparatorAt( position:int ):void
{
if (menuCollection[( position )] == null) {
return;
}
var item:ContextMenuItem = menuCollection[( position )];
item.separatorBefore = false;
}

public function addSeparatorAt( position:int ):void
{
if ( position < 1 || position > menuCollection.length )
return;

var item:ContextMenuItem = menuCollection[( position )];
item.separatorBefore = true;
}

private function buildCustomMenus():void
{
customContextMenu.customItems = [];
for ( var i:int = 0; i < menuCollection.length; i++ ) {
customContextMenu.customItems.push( menuCollection[i] );
}
contectMenuObject.contextMenu = customContextMenu;
}
}
}

Written by Deepanjan Das

June 19, 2010 at 10:18 PM

Converting a Vector to Array

leave a comment »

public function vectorToArray( value:* ) : Array
{
var vectorCount:int = value.length;
var newArray:Array = new Array();
for( var i:int = 0; i < vectorCount; i++ ){
newArray[i] = value[i];
}
return newArray;
}

Written by Deepanjan Das

June 13, 2010 at 7:30 AM