You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ti...@apache.org on 2012/01/06 21:58:45 UTC

svn commit: r1228400 [3/6] - in /incubator/flex/whiteboard/navigators: ./ .settings/ src/ src/ws/ src/ws/tink/ src/ws/tink/spark/ src/ws/tink/spark/containers/ src/ws/tink/spark/containers/supportClasses/ src/ws/tink/spark/controls/ src/ws/tink/spark/c...

Added: incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/DataAccordion.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/DataAccordion.as?rev=1228400&view=auto
==============================================================================
--- incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/DataAccordion.as (added)
+++ incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/DataAccordion.as Fri Jan  6 20:58:43 2012
@@ -0,0 +1,688 @@
+/*
+
+Copyright (c) 2010 Tink Ltd - http://www.tink.ws
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
+the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
+THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+*/
+
+package ws.tink.spark.controls
+{
+	import mx.utils.BitFlagUtil;
+	
+	import spark.components.supportClasses.ButtonBarBase;
+	import spark.effects.easing.IEaser;
+	import spark.layouts.supportClasses.LayoutBase;
+	
+	import ws.tink.spark.layouts.AccordionLayout;
+	
+	import mx.utils.BitFlagUtil;
+	
+
+	
+	/**
+	 *  An Spark DataAccordion navigator displays a list of items,
+	 *  but only one of them at a time is fully visible.
+	 *  It creates and manages navigator buttons, which you use
+	 *  to navigate between the elements.
+	 *  There is one navigator button associated with each element,
+	 *  and each navigator button belongs to the Accordion container, not to the child.
+	 *  When the user clicks a navigator button, the associated element
+	 *  is displayed.
+	 *  The transition to the new child uses an animation to make it clear to
+	 *  the user that one child is disappearing and a different one is appearing.
+	 * 
+	 *  @mxml
+	 *
+	 *  <p>The <code>&lt;st:DataAccordion&gt;</code> tag inherits all of the
+	 *  tag attributes of its superclass, and adds the following tag attributes:</p>
+	 *
+	 *  <pre>
+	 *  &lt;st:DataAccordion
+	 *    <strong>Properties</strong>
+	 *    buttonRotation="none|left|right"
+	 *    direction="vertical|horizontal"
+	 *    duration="700"
+	 *    easer=""<i>IEaser</i>""
+	 *    labelField="label"
+	 *    labelFunction="null"
+	 *    minElementSize="0"
+	 *    useScrollRect"true"
+	 *  
+	 *    <strong>Styles</strong>
+	 *    <strong>Events</strong>
+	 *  /&gt;
+	 *  </pre>
+	 *
+	 *  @includeExample examples/DataAccordionExample.mxml
+	 *
+	 *  @see ws.tink.spark.layouts.AccordionLayout
+	 *
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	public class DataAccordion extends DataNavigator
+	{
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Class constants
+		//
+		//--------------------------------------------------------------------------
+		
+		// Constants used for accordionLayout proxied properties.
+		
+		/**
+		 *  @private
+		 */
+		private static const BUTTON_ROTATION_PROPERTY_FLAG:uint = 1 << 0;
+		
+		/**
+		 *  @private
+		 */
+		private static const DIRECTION_PROPERTY_FLAG:uint = 1 << 1;
+		
+		/**
+		 *  @private
+		 */
+		private static const DURATION_PROPERTY_FLAG:uint = 1 << 2;
+		
+		/**
+		 *  @private
+		 */
+		private static const EASER_PROPERTY_FLAG:uint = 1 << 3;
+		
+		/**
+		 *  @private
+		 */
+		private static const MIN_ELEMENT_SIZE_PROPERTY_FLAG:uint = 1 << 4;
+		
+		/**
+		 *  @private
+		 */
+		private static const USE_SCROLL_RECT_PROPERTY_FLAG:uint = 1 << 5;
+		
+		/**
+		 *  @private
+		 */
+		private static const USE_VIRTUAL_LAYOUT_PROPERTY_FLAG:uint = 1 << 6;
+		
+		
+		// Constants used for buttonBar proxied properties.
+		
+		/**
+		 *  @private
+		 */
+		private static const LABEL_FIELD_PROPERTY_FLAG:uint = 1 << 0;
+		
+		/**
+		 *  @private
+		 */
+		private static const LABEL_FUNCTION_PROPERTY_FLAG:uint = 1 << 1;
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constructor. 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function DataAccordion()
+		{
+			super();
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Skin Parts
+		//
+		//--------------------------------------------------------------------------
+		
+		//----------------------------------
+		//  buttonBar
+		//---------------------------------- 
+		
+		[SkinPart(required="true")]
+		
+		/**
+		 *  A required skin part that is used to navigate between elements.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public var buttonBar:ButtonBarBase;
+		
+		
+		//----------------------------------
+		//  accordionLayout
+		//---------------------------------- 
+		
+		[SkinPart(required="true")]
+		
+		/**
+		 *  A required skin part that defines the layout for the Accordion.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public var accordionLayout:AccordionLayout;
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Properties proxied to accordionLayout
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 *  Several properties are proxied to accordionLayout.  However, when accordionLayout
+		 *  is not around, we need to store values set on Accordion.  This object 
+		 *  stores those values.  If accordionLayout is around, the values are stored 
+		 *  on the accordionLayout directly.  However, we need to know what values 
+		 *  have been set by the developer on the Accordion (versus set on 
+		 *  the accordionLayout or defaults of the accordionLayout) as those are values 
+		 *  we want to carry around if the accordionLayout changes (via a new skin). 
+		 *  In order to store this info effeciently, _accordionLayoutProperties becomes 
+		 *  a uint to store a series of BitFlags.  These bits represent whether a 
+		 *  property has been explicitely set on this Accordion.  When the 
+		 *  accordionLayout is not around, _accordionLayoutProperties is a typeless 
+		 *  object to store these proxied properties.  When accordionLayout is around,
+		 *  _accordionLayoutProperties stores booleans as to whether these properties 
+		 *  have been explicitely set or not.
+		 */
+		private var _accordionLayoutProperties:Object = {};
+		
+		
+		//----------------------------------
+		//  buttonRotation
+		//----------------------------------    
+		
+		[Inspectable(category="General", enumeration="none,left,right", defaultValue="none")]
+		
+		/** 
+		 *  @copy ws.tink.spark.layouts.AccordionLayout#buttonRotation
+		 */
+		public function get buttonRotation():String
+		{
+			return accordionLayout ? accordionLayout.buttonRotation : _accordionLayoutProperties.buttonRotation ;
+		}
+		/**
+		 *  @private
+		 */
+		public function set buttonRotation( value:String ):void
+		{
+			if( value == buttonRotation ) return;
+			
+			if( accordionLayout )
+			{
+				accordionLayout.buttonRotation = value;
+				_accordionLayoutProperties = BitFlagUtil.update( _accordionLayoutProperties as uint, BUTTON_ROTATION_PROPERTY_FLAG, true );
+			}
+			else
+			{
+				_accordionLayoutProperties.buttonRotation = value;
+			}
+		}
+		
+		
+		//----------------------------------
+		//  direction
+		//----------------------------------    
+		
+		[Inspectable(category="General", enumeration="vertical,horizontal", defaultValue="vertical")]
+		
+		/** 
+		 *  @copy ws.tink.spark.layouts.AccordionLayout#direction
+		 */
+		public function get direction():String
+		{
+			return accordionLayout ? accordionLayout.direction : _accordionLayoutProperties.direction;
+		}
+		/**
+		 *  @private
+		 */
+		public function set direction( value:String ):void
+		{
+			if( value == direction ) return;
+			
+			if( accordionLayout )
+			{
+				accordionLayout.direction = value;
+				_accordionLayoutProperties = BitFlagUtil.update( _accordionLayoutProperties as uint, DIRECTION_PROPERTY_FLAG, true );
+			}
+			else
+			{
+				_accordionLayoutProperties.direction = value;
+			}
+		}
+		
+		
+		//----------------------------------
+		//  duration
+		//----------------------------------    
+		
+		/**
+		 *  @copy ws.tink.spark.layouts.AccordionLayout#duration
+		 */
+		public function get duration():Number
+		{
+			return accordionLayout ? accordionLayout.duration : _accordionLayoutProperties.duration;
+		}
+		/**
+		 *  @private
+		 */
+		public function set duration(value:Number):void
+		{
+			if( duration == value ) return;
+			
+			if( accordionLayout )
+			{
+				accordionLayout.duration = value;
+				_accordionLayoutProperties = BitFlagUtil.update( _accordionLayoutProperties as uint, DURATION_PROPERTY_FLAG, true );
+			}
+			else
+			{
+				_accordionLayoutProperties.duration = value;
+			}
+		}
+		
+		
+		
+		//----------------------------------
+		//  easer
+		//----------------------------------    
+		
+		/**
+		 *  @copy ws.tink.spark.layouts.AccordionLayout#easer
+		 */
+		public function get easer():IEaser
+		{
+			return accordionLayout ? accordionLayout.easer : _accordionLayoutProperties.easer;
+		}
+		/**
+		 *  @private
+		 */
+		public function set easer(value:IEaser):void
+		{
+			if( easer == value ) return;
+			
+			if( accordionLayout )
+			{
+				accordionLayout.easer = value;
+				_accordionLayoutProperties = BitFlagUtil.update( _accordionLayoutProperties as uint, EASER_PROPERTY_FLAG, true );
+			}
+			else
+			{
+				_accordionLayoutProperties.easer = value;
+			}
+		}
+		
+		
+		//----------------------------------
+		//  minElementSize
+		//----------------------------------    
+		
+		/** 
+		 *  @copy ws.tink.spark.layouts.AccordionLayout#minElementSize
+		 */
+		public function get minElementSize():Number
+		{
+			return accordionLayout ? accordionLayout.minElementSize : _accordionLayoutProperties.minElementSize;
+		}
+		/**
+		 *  @private
+		 */
+		public function set minElementSize( value:Number ):void
+		{
+			if( minElementSize == value ) return;
+			
+			if( accordionLayout )
+			{
+				accordionLayout.minElementSize = value;
+				_accordionLayoutProperties = BitFlagUtil.update( _accordionLayoutProperties as uint, MIN_ELEMENT_SIZE_PROPERTY_FLAG, true );
+			}
+			else
+			{
+				_accordionLayoutProperties.minElementSize = value;
+			}
+		}
+		
+		
+		//----------------------------------
+		//  useScrollRect
+		//----------------------------------    
+		
+		/**
+		 *  @copy ws.tink.spark.layouts.AccordionLayout#useScrollRect
+		 */
+		public function get useScrollRect():Boolean
+		{
+			return accordionLayout ? accordionLayout.useScrollRect : _accordionLayoutProperties.useScrollRect;
+		}
+		/**
+		 *  @private
+		 */
+		public function set useScrollRect( value:Boolean ):void
+		{
+			if( useScrollRect == value ) return;
+			
+			if( accordionLayout )
+			{
+				accordionLayout.useScrollRect = value;
+				_accordionLayoutProperties = BitFlagUtil.update( _accordionLayoutProperties as uint, USE_SCROLL_RECT_PROPERTY_FLAG, true );
+			}
+			else
+			{
+				_accordionLayoutProperties.useScrollRect = value;
+			}
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Properties proxied to buttonBar
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 *  Several properties are proxied to buttonBar.  However, when buttonBar
+		 *  is not around, we need to store values set on Accordion.  This object 
+		 *  stores those values.  If buttonBar is around, the values are stored 
+		 *  on the buttonBar directly.  However, we need to know what values 
+		 *  have been set by the developer on the Accordion (versus set on 
+		 *  the buttonBar or defaults of the buttonBar) as those are values 
+		 *  we want to carry around if the buttonBar changes (via a new skin). 
+		 *  In order to store this info effeciently, _buttonBarProperties becomes 
+		 *  a uint to store a series of BitFlags.  These bits represent whether a 
+		 *  property has been explicitely set on this Accordion.  When the 
+		 *  buttonBar is not around, _buttonBarProperties is a typeless 
+		 *  object to store these proxied properties.  When buttonBar is around,
+		 *  _buttonBarProperties stores booleans as to whether these properties 
+		 *  have been explicitely set or not.
+		 */
+		private var _buttonBarProperties:Object = {};
+		
+		
+		
+		//----------------------------------
+		//  labelField
+		//----------------------------------
+		
+		/**
+		 *  @copy spark.components.supportClasses.ListBase#labelField
+		 */
+//		public function get labelField():String
+//		{
+//			return buttonBar ? buttonBar.labelField : _buttonBarProperties.labelField;
+//		}
+		
+		/**
+		 *  @private
+		 */
+		override public function set labelField( value:String ):void
+		{
+			super.labelField = value;
+			
+			if( labelField == value ) return 
+			
+			if( buttonBar )
+			{
+				buttonBar.labelField = value;
+				_buttonBarProperties = BitFlagUtil.update( _buttonBarProperties as uint, LABEL_FIELD_PROPERTY_FLAG, true );
+			}
+			else
+			{
+				_buttonBarProperties.labelField = value;
+			}
+		}
+		
+		
+		//----------------------------------
+		//  labelFunction
+		//----------------------------------
+		
+		/**
+		 *  @copy spark.components.supportClasses.ListBase#labelFunction
+		 */
+//		public function get labelFunction():Function
+//		{
+//			return buttonBar ? buttonBar.labelFunction : _buttonBarProperties.labelFunction;
+//		}
+		
+		/**
+		 *  @private
+		 */
+		override public function set labelFunction( value:Function ):void
+		{
+			super.labelFunction = value;
+			
+			if( labelFunction == value ) return; 
+			
+			if( buttonBar )
+			{
+				buttonBar.labelFunction = value;
+				_buttonBarProperties = BitFlagUtil.update( _buttonBarProperties as uint, LABEL_FUNCTION_PROPERTY_FLAG, true );
+			}
+			else
+			{
+				_buttonBarProperties.labelFunction = value;
+			}
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden Properties
+		//
+		//--------------------------------------------------------------------------
+		
+		//----------------------------------
+		//  layout
+		//----------------------------------    
+		
+		/**
+		 *  @private
+		 */
+		override public function set layout( value:LayoutBase ):void
+		{
+			throw( new Error( resourceManager.getString( "components", "layoutReadOnly" ) ) );
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden Methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @inheritDoc
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override protected function partAdded(partName:String, instance:Object):void
+		{
+			super.partAdded( partName, instance );
+			
+			switch( instance )
+			{
+				case accordionLayout :
+				{
+					// copy proxied values from _accordionLayoutProperties (if set) to accordionLayout
+					var newAccordionLayoutProperties:uint = 0;
+					
+					if( _accordionLayoutProperties.buttonRotation !== undefined )
+					{
+						accordionLayout.buttonRotation = _accordionLayoutProperties.buttonRotation;
+						newAccordionLayoutProperties = BitFlagUtil.update( newAccordionLayoutProperties as uint, BUTTON_ROTATION_PROPERTY_FLAG, true );
+					}
+					
+					if( _accordionLayoutProperties.direction !== undefined )
+					{
+						accordionLayout.direction = _accordionLayoutProperties.direction;
+						newAccordionLayoutProperties = BitFlagUtil.update( newAccordionLayoutProperties as uint, DIRECTION_PROPERTY_FLAG, true );
+					}
+					
+					if( _accordionLayoutProperties.duration !== undefined )
+					{
+						accordionLayout.duration = _accordionLayoutProperties.duration;
+						newAccordionLayoutProperties = BitFlagUtil.update( newAccordionLayoutProperties as uint, DURATION_PROPERTY_FLAG, true );
+					}
+					
+					if( _accordionLayoutProperties.easer !== undefined )
+					{
+						accordionLayout.easer = _accordionLayoutProperties.easer;
+						newAccordionLayoutProperties = BitFlagUtil.update( newAccordionLayoutProperties as uint, EASER_PROPERTY_FLAG, true );
+					}
+					
+					if( _accordionLayoutProperties.minElementSize !== undefined )
+					{
+						accordionLayout.minElementSize = _accordionLayoutProperties.minElementSize;
+						newAccordionLayoutProperties = BitFlagUtil.update( newAccordionLayoutProperties as uint, MIN_ELEMENT_SIZE_PROPERTY_FLAG, true );
+					}
+					
+					if( _accordionLayoutProperties.useScrollRect !== undefined )
+					{
+						accordionLayout.useScrollRect = _accordionLayoutProperties.useScrollRect;
+						newAccordionLayoutProperties = BitFlagUtil.update( newAccordionLayoutProperties as uint, USE_SCROLL_RECT_PROPERTY_FLAG, true );
+					}
+					
+					if( _accordionLayoutProperties.useVirtualLayout !== undefined )
+					{
+						accordionLayout.useVirtualLayout = _accordionLayoutProperties.useVirtualLayout;
+						newAccordionLayoutProperties = BitFlagUtil.update( newAccordionLayoutProperties as uint, USE_VIRTUAL_LAYOUT_PROPERTY_FLAG, true );
+					}
+					
+					_accordionLayoutProperties = newAccordionLayoutProperties;
+					
+					if( buttonBar ) accordionLayout.buttonBar = buttonBar;
+					break;
+				}
+				case buttonBar :
+				{// copy proxied values from _buttonBarProperties (if set) to buttonBar
+					var newButtonBarProperties:uint = 0;
+					
+					if( _buttonBarProperties.labelField !== undefined )
+					{
+						buttonBar.labelField = _buttonBarProperties.labelField;
+						newButtonBarProperties = BitFlagUtil.update( newButtonBarProperties as uint, LABEL_FIELD_PROPERTY_FLAG, true );
+					}
+					
+					if( _buttonBarProperties.labelFunction !== undefined )
+					{
+						buttonBar.labelFunction = _buttonBarProperties.labelFunction;
+						newButtonBarProperties = BitFlagUtil.update( newButtonBarProperties as uint, LABEL_FUNCTION_PROPERTY_FLAG, true );
+					}
+					
+					_buttonBarProperties = newButtonBarProperties;
+					
+					buttonBar.dataProvider = this;
+					if( accordionLayout ) accordionLayout.buttonBar = buttonBar;
+					break;
+				}
+			}
+		}
+		
+		/**
+		 *  @inheritDoc
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override protected function partRemoved( partName:String, instance:Object ):void
+		{
+			super.partRemoved( partName, instance );
+			
+			switch( instance )
+			{
+				case accordionLayout :
+				{
+					// copy proxied values from accordionLayout (if explicitly set) to _accordionLayoutProperties
+					var newAccordionLayoutProperties:Object = {};
+					
+					if ( BitFlagUtil.isSet( _accordionLayoutProperties as uint, BUTTON_ROTATION_PROPERTY_FLAG ) )
+						newAccordionLayoutProperties.buttonRotation = accordionLayout.buttonRotation;
+					
+					if ( BitFlagUtil.isSet( _accordionLayoutProperties as uint, DIRECTION_PROPERTY_FLAG ) )
+						newAccordionLayoutProperties.direction = accordionLayout.direction;
+					
+					if ( BitFlagUtil.isSet( _accordionLayoutProperties as uint, DURATION_PROPERTY_FLAG ) )
+						newAccordionLayoutProperties.duration = accordionLayout.duration;
+					
+					if ( BitFlagUtil.isSet( _accordionLayoutProperties as uint, EASER_PROPERTY_FLAG ) )
+						newAccordionLayoutProperties.easer = accordionLayout.easer;
+					
+					if ( BitFlagUtil.isSet( _accordionLayoutProperties as uint, MIN_ELEMENT_SIZE_PROPERTY_FLAG ) )
+						newAccordionLayoutProperties.minElementSize = accordionLayout.minElementSize;
+					
+					if ( BitFlagUtil.isSet( _accordionLayoutProperties as uint, USE_SCROLL_RECT_PROPERTY_FLAG ) )
+						newAccordionLayoutProperties.useScrollRect = accordionLayout.useScrollRect;
+					
+					if ( BitFlagUtil.isSet( _accordionLayoutProperties as uint, USE_VIRTUAL_LAYOUT_PROPERTY_FLAG ) )
+						newAccordionLayoutProperties.useVirtualLayout = accordionLayout.useVirtualLayout;
+					
+					_accordionLayoutProperties = newAccordionLayoutProperties;
+					break;
+				}
+				case buttonBar :
+				{
+					// copy proxied values from buttonBar (if explicitly set) to _buttonBarProperties
+					var newButtonBarProperties:Object = {};
+					
+					if ( BitFlagUtil.isSet( _buttonBarProperties as uint, LABEL_FIELD_PROPERTY_FLAG ) )
+						newButtonBarProperties.labelField = buttonBar.labelField;
+					
+					if ( BitFlagUtil.isSet( _buttonBarProperties as uint, LABEL_FUNCTION_PROPERTY_FLAG ) )
+						newButtonBarProperties.labelFunction = buttonBar.labelFunction;
+					
+					_buttonBarProperties = newButtonBarProperties;
+					
+					if( accordionLayout ) accordionLayout.buttonBar = null;
+					break;
+				}
+			}
+		}
+	}
+}
\ No newline at end of file

Added: incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/DataNavigator.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/DataNavigator.as?rev=1228400&view=auto
==============================================================================
--- incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/DataNavigator.as (added)
+++ incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/DataNavigator.as Fri Jan  6 20:58:43 2012
@@ -0,0 +1,1472 @@
+/*
+Copyright (c) 2010 Tink Ltd - http://www.tink.ws
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
+the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
+THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+package ws.tink.spark.controls
+{
+	import flash.events.Event;
+	
+	import mx.collections.ArrayList;
+	import mx.collections.IList;
+	import mx.core.IDataRenderer;
+	import mx.core.IFactory;
+	import mx.core.ISelectableList;
+	import mx.core.IVisualElement;
+	import mx.core.mx_internal;
+	import mx.events.CollectionEvent;
+	import mx.events.CollectionEventKind;
+	import mx.events.FlexEvent;
+	import mx.utils.BitFlagUtil;
+	
+	import spark.components.IItemRenderer;
+	import spark.components.IItemRendererOwner;
+	import spark.components.supportClasses.SkinnableContainerBase;
+	import spark.events.IndexChangeEvent;
+	import spark.events.RendererExistenceEvent;
+	import spark.layouts.supportClasses.LayoutBase;
+	import spark.utils.LabelUtil;
+	
+	import ws.tink.spark.layouts.supportClasses.AnimationNavigatorLayoutBase;
+	import ws.tink.spark.layouts.supportClasses.INavigatorLayout;
+	
+	use namespace mx_internal;
+	
+	//--------------------------------------
+	//  Events
+	//--------------------------------------
+	
+	/**
+	 *  Dispatched when the ISelectableList has been updated in some way.
+	 *
+	 *  @eventType mx.events.CollectionEvent.COLLECTION_CHANGE
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 9
+	 *  @playerversion AIR 1.1
+	 *  @productversion Flex 3
+	 */
+	[Event(name="collectionChange", type="mx.events.CollectionEvent")]
+	
+	/**
+	 *  Dispatched after the selection has changed. 
+	 *  This event is dispatched when the user interacts with the control.
+	 * 
+	 *  <p>When you change the value of the <code>selectedIndex</code> 
+	 *  or <code>selectedItem</code> properties programmatically, 
+	 *  the control does not dispatch the <code>change</code> event. 
+	 *  It dispatches the <code>valueCommit</code> event instead.</p>
+	 *
+	 *  @eventType spark.events.IndexChangeEvent.CHANGE
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	[Event(name="change", type="spark.events.IndexChangeEvent")]
+	
+	/**
+	 *  Dispatched when a renderer is added to the container.
+	 *  The <code>event.renderer</code> property contains 
+	 *  the renderer that was added.
+	 *
+	 *  @eventType spark.events.RendererExistenceEvent.RENDERER_ADD
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	[Event(name="rendererAdd", type="spark.events.RendererExistenceEvent")]
+	
+	/**
+	 *  Dispatched when a renderer is removed from the container.
+	 *  The <code>event.renderer</code> property contains 
+	 *  the renderer that was removed.
+	 *
+	 *  @eventType spark.events.RendererExistenceEvent.RENDERER_REMOVE
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	[Event(name="rendererRemove", type="spark.events.RendererExistenceEvent")]
+	
+//	include "../styles/metadata/BasicInheritingTextStyles.as"
+	
+	/**
+	 *  The alpha of the focus ring for this component.
+	 *
+	 *  @default 0.55
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	[Style(name="focusAlpha", type="Number", inherit="no", theme="spark", minValue="0.0", maxValue="1.0")]
+	
+	/**
+	 *  Color of focus ring when the component is in focus.
+	 *
+	 *  @default 0x70B2EE
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */ 
+	[Style(name="focusColor", type="uint", format="Color", inherit="yes", theme="spark")]
+	
+	/**
+	 *  Thickness, in pixels, of the focus rectangle outline.
+	 *
+	 *  @default 2
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 9
+	 *  @playerversion AIR 1.1
+	 *  @productversion Flex 3
+	 */
+	[Style(name="focusThickness", type="Number", format="Length", inherit="no", minValue="0.0")]
+	
+	/**
+	 *  The alpha of the border for this component.
+	 *
+	 *  @default 1.0
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	[Style(name="borderAlpha", type="Number", inherit="no", theme="spark", minValue="0.0", maxValue="1.0")]
+	
+	/**
+	 *  The color of the border for this component.
+	 *
+	 *   @default #696969
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	[Style(name="borderColor", type="uint", format="Color", inherit="no", theme="spark")]
+	
+	/**
+	 *  Controls the visibility of the border for this component.
+	 *
+	 *  @default true
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	[Style(name="borderVisible", type="Boolean", inherit="no", theme="spark")]
+	
+	/**
+	 *  The alpha of the content background for this component.
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	[Style(name="contentBackgroundAlpha", type="Number", inherit="yes", theme="spark", minValue="0.0", maxValue="1.0")]
+	
+	/**
+	 *  @copy spark.components.supportClasses.GroupBase#style:contentBackgroundColor
+	 *   
+	 *  @default 0xFFFFFF
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	[Style(name="contentBackgroundColor", type="uint", format="Color", inherit="yes", theme="spark")]
+	
+	[DefaultProperty("dataProvider")]
+	
+	//[IconFile("SkinnableDataContainer.png")]
+	
+	/**
+	 *  The SkinnableDataContainer class is the base container class for
+	 *  data items.  The SkinnableDataContainer class converts data 
+	 *  items to visual elements for display.
+	 *  While this container can hold visual elements, it is often used only 
+	 *  to hold data items as children.
+	 *
+	 *  <p>The SkinnableDataContainer class takes as children data items 
+	 *  or visual elements that implement the IVisualElement interface
+	 *  and are Display Objects.
+	 *  Data items can be simple data items such String and Number objects, 
+	 *  and more complicated data items such as Object and XMLNode objects. 
+	 *  While these containers can hold visual elements, 
+	 *  they are often used only to hold data items as children.</p>
+	 *
+	 *  <p>An item renderer defines the visual representation of the 
+	 *  data item in the container. 
+	 *  The item renderer converts the data item into a format that can 
+	 *  be displayed by the container. 
+	 *  You must pass an item renderer to a SkinnableDataContainer to 
+	 *  render data items appropriately.</p>
+	 *
+	 *  <p>If you want a container of data items and don't need a skin, then 
+	 *  it is recommended to use a DataGroup (which cannot be skinned) to 
+	 *  improve performance and application size.</p>
+	 *
+	 *  <p>The SkinnableDataContainer container has the following default characteristics:</p>
+	 *  <table class="innertable">
+	 *     <tr><th>Characteristic</th><th>Description</th></tr>
+	 *     <tr><td>Default size</td><td>Large enough to display its children</td></tr>
+	 *     <tr><td>Minimum size</td><td>0 pixels</td></tr>
+	 *     <tr><td>Maximum size</td><td>10000 pixels wide and 10000 pixels high</td></tr>
+	 *  </table>
+	 * 
+	 *  @mxml
+	 *
+	 *  <p>The <code>&lt;s:SkinnableDataContainer&gt;</code> tag inherits all of the tag 
+	 *  attributes of its superclass and adds the following tag attributes:</p>
+	 *
+	 *  <pre>
+	 *  &lt;s:SkinnableDataContainer
+	 *    <strong>Properties</strong>
+	 *    autoLayout="true"
+	 *    dataProvider="null"
+	 *    itemRenderer="null"
+	 *    itemRendererFunction="null"
+	 *    layout="VerticalLayout"
+	 *    typicalItem="null"
+	 *  
+	 *    <strong>Styles</strong>
+	 *    alignmentBaseline="useDominantBaseline"
+	 *    baselineShift="0.0"
+	 *    cffHinting="horizontal_stem"
+	 *    color="0"
+	 *    digitCase="default"
+	 *    digitWidth="default"
+	 *    direction="LTR"
+	 *    dominantBaseline="auto"
+	 *    focusAlpha="0.55"
+	 *    focusColor=""
+	 *    focusThickness="2"
+	 *    fontFamily="Times New Roman"
+	 *    fontLookup="device"
+	 *    fontSize="12"
+	 *    fontStyle="normal"
+	 *    fontWeight="normal"
+	 *    justificationRule="auto"
+	 *    justificationStyle="auto"
+	 *    kerning="auto"
+	 *    ligatureLevel="common"
+	 *    lineHeight="120%"
+	 *    lineThrough="false"
+	 *    locale="en"
+	 *    renderingMode="CFF"
+	 *    textAlign="start"
+	 *    textAlignLast="start"
+	 *    textAlpha="1"
+	 *    textJustify="inter_word"
+	 *    trackingLeft="0"
+	 *    trackingRight="0"
+	 *    typographicCase="default"
+	 *  
+	 *    <strong>Events</strong>
+	 *    rendererAdd="<i>No default</i>"
+	 *    rendererRemove="<i>No default</i>"
+	 *  /&gt;
+	 *  </pre>
+	 *
+	 *  @see SkinnableContainer
+	 *  @see DataGroup
+	 *  @see spark.skins.spark.SkinnableDataContainerSkin
+	 *
+	 *  @includeExample examples/SkinnableDataContainerExample.mxml
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	public class DataNavigator extends SkinnableContainerBase implements IItemRendererOwner, ISelectableList
+	{
+//			include "../core/Version.as";
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Class constants
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 */
+		private static const AUTO_LAYOUT_PROPERTY_FLAG:uint = 1 << 0;
+		
+		/**
+		 *  @private
+		 */
+		private static const DATA_PROVIDER_PROPERTY_FLAG:uint = 1 << 1;
+		
+		/**
+		 *  @private
+		 */
+		private static const ITEM_RENDERER_PROPERTY_FLAG:uint = 1 << 2;
+		
+		/**
+		 *  @private
+		 */
+		private static const ITEM_RENDERER_FUNCTION_PROPERTY_FLAG:uint = 1 << 3;
+		
+		/**
+		 *  @private
+		 */
+		private static const LAYOUT_PROPERTY_FLAG:uint = 1 << 4;
+		
+		/**
+		 *  @private
+		 */
+		private static const TYPICAL_ITEM_PROPERTY_FLAG:uint = 1 << 5;
+		
+		/**
+		 *  @private
+		 */
+		private static const SELECTED_INDEX_PROPERTY_FLAG:uint = 1 << 6;
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constructor. 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function DataNavigator()
+		{
+			super();
+			
+			useVirtualLayout = true;
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Skin Parts
+		//
+		//--------------------------------------------------------------------------
+		
+		[SkinPart(required="false")]
+		
+		/**
+		 *  An optional skin part that defines the DataGroup in the skin class 
+		 *  where data items get pushed into, rendered, and laid out.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public var contentGroup:DataNavigatorGroup;
+		
+		/**
+		 *  @private
+		 *  Several properties are proxied to contentGroup.  However, when contentGroup
+		 *  is not around, we need to store values set on SkinnableDataContainer.  This object 
+		 *  stores those values.  If contentGroup is around, the values are stored 
+		 *  on the contentGroup directly.  However, we need to know what values 
+		 *  have been set by the developer on the SkinnableDataContainer (versus set on 
+		 *  the contentGroup or defaults of the contentGroup) as those are values 
+		 *  we want to carry around if the contentGroup changes (via a new skin). 
+		 *  In order to store this info effeciently, dataGroupProperties becomes 
+		 *  a uint to store a series of BitFlags.  These bits represent whether a 
+		 *  property has been explicitly set on this SkinnableDataContainer.  When the 
+		 *  contentGroup is not around, dataGroupProperties is a typeless 
+		 *  object to store these proxied properties.  When contentGroup is around,
+		 *  dataGroupProperties stores booleans as to whether these properties 
+		 *  have been explicitly set or not.
+		 */
+		private var dataGroupProperties:Object = {};
+		
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Properties 
+		//
+		//--------------------------------------------------------------------------
+		
+		//----------------------------------
+		//  selectedIndex
+		//---------------------------------- 
+		
+		[Bindable("change")]
+		[Bindable("valueCommit")]
+		
+		/**
+		 *  @copy ws.tink.spark.controls.DataNavigatorGroup#selectedIndex
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get selectedIndex():int
+		{
+			return contentGroup ? contentGroup.selectedIndex : dataGroupProperties.selectedIndex;
+		}
+		/**
+		 *  @private
+		 */
+		public function set selectedIndex( value:int ):void
+		{
+			if( value == selectedIndex ) return;
+			
+			if (contentGroup)
+			{
+				contentGroup.selectedIndex = value;
+				dataGroupProperties = BitFlagUtil.update(dataGroupProperties as uint, 
+					SELECTED_INDEX_PROPERTY_FLAG, true);
+			}
+			else
+				dataGroupProperties.selectedIndex = value;
+		}
+		
+		
+		
+		//----------------------------------
+		//  selectedItem
+		//---------------------------------- 
+		
+		[Bindable("change")]
+		[Bindable("valueCommit")]
+		
+		/**
+		 *  @copy ws.tink.spark.controls.DataNavigatorGroup#selectedItem
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get selectedItem():Object
+		{
+			var index:int = selectedIndex;
+			return index != -1 ? dataProvider.getItemAt( index ) : null;
+		}
+		/**
+		 *  @private
+		 */
+		public function set selectedItem( value:Object ):void
+		{
+			if( dataProvider )
+			{
+				var index:int = dataProvider.getItemIndex( value );
+				if( index != -1 ) selectedIndex = index;
+			}
+		}
+		
+		
+		
+		//----------------------------------
+		//  useVirtualLayout
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 */
+		private var _useVirtualLayout:Boolean = true;
+		
+		/**
+		 *  Sets the value of the <code>useVirtualLayout</code> property
+		 *  of the layout associated with this control.  
+		 *  If the layout is subsequently replaced and the value of this 
+		 *  property is <code>true</code>, then the new layout's 
+		 *  <code>useVirtualLayout</code> property is set to <code>true</code>.
+		 *
+		 *  @default true
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get useVirtualLayout():Boolean
+		{
+			return layout ? layout.useVirtualLayout : _useVirtualLayout;
+		}
+		/**
+		 *  @private
+		 *  Note: this property deviates a little from the conventional delegation pattern.
+		 *  If the user explicitly sets ListBase.useVirtualLayout=false and then sets
+		 *  the layout property to a layout with useVirtualLayout=true, the layout's value
+		 *  for this property trumps the ListBase.  The convention dictates opposite
+		 *  however in this case, always honoring the layout's useVirtalLayout property seems 
+		 *  less likely to cause confusion.
+		 */
+		public function set useVirtualLayout(value:Boolean):void
+		{
+			if( value == useVirtualLayout ) return;
+			
+			_useVirtualLayout = value;
+			if ( layout ) layout.useVirtualLayout = value;
+		}
+		
+		
+		//----------------------------------
+		//  length
+		//---------------------------------- 
+		
+		/**
+		 *  @copy ws.tink.spark.controls.DataNavigatorGroup#length
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get length():int
+		{
+			return dataProvider ? dataProvider.length : 0;
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Properties proxied to contentGroup
+		//
+		//--------------------------------------------------------------------------
+		
+		
+		
+		
+		//----------------------------------
+		//  labelField
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 */
+		private var _labelField:String = "label";
+		
+		/**
+		 *  @private
+		 */
+		private var _labelFieldOrFunctionChanged:Boolean; 
+		
+		/**
+		 *  The name of the field in the data provider items to display 
+		 *  as the label. 
+		 *  The <code>labelFunction</code> property overrides this property.
+		 *
+		 *  @default "label" 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get labelField():String
+		{
+			return _labelField;
+		}
+		
+		/**
+		 *  @private
+		 */
+		public function set labelField(value:String):void
+		{
+			if (value == _labelField)
+				return 
+				
+				_labelField = value;
+			_labelFieldOrFunctionChanged = true;
+			invalidateProperties();
+		}
+		
+		//----------------------------------
+		//  labelFunction
+		//----------------------------------
+		
+		/**
+		 *  @private
+		 */
+		private var _labelFunction:Function; 
+		
+		/**
+		 *  A user-supplied function to run on each item to determine its label.  
+		 *  The <code>labelFunction</code> property overrides 
+		 *  the <code>labelField</code> property.
+		 *
+		 *  <p>You can supply a <code>labelFunction</code> that finds the 
+		 *  appropriate fields and returns a displayable string. The 
+		 *  <code>labelFunction</code> is also good for handling formatting and 
+		 *  localization. </p>
+		 *
+		 *  <p>The label function takes a single argument which is the item in 
+		 *  the data provider and returns a String.</p>
+		 *  <pre>
+		 *  myLabelFunction(item:Object):String</pre>
+		 *
+		 *  @default null
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get labelFunction():Function
+		{
+			return _labelFunction;
+		}
+		
+		/**
+		 *  @private
+		 */
+		public function set labelFunction(value:Function):void
+		{
+			if (value == _labelFunction)
+				return 
+				
+				_labelFunction = value;
+			_labelFieldOrFunctionChanged = true;
+			invalidateProperties(); 
+		}
+		
+		
+		
+		
+		
+		//----------------------------------
+		//  autoLayout
+		//----------------------------------
+		
+		[Inspectable(defaultValue="true")]
+		
+		/**
+		 *  @copy spark.components.supportClasses.GroupBase#autoLayout
+		 *
+		 *  @default true
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get autoLayout():Boolean
+		{
+			if (contentGroup)
+				return contentGroup.autoLayout;
+			else
+			{
+				// want the default to be true
+				var v:* = dataGroupProperties.autoLayout;
+				return (v === undefined) ? true : v;
+			}
+		}
+		
+		/**
+		 *  @private
+		 */
+		public function set autoLayout(value:Boolean):void
+		{
+			if (contentGroup)
+			{
+				contentGroup.autoLayout = value;
+				dataGroupProperties = BitFlagUtil.update(dataGroupProperties as uint, 
+					AUTO_LAYOUT_PROPERTY_FLAG, true);
+			}
+			else
+				dataGroupProperties.autoLayout = value;
+		}
+		
+		//----------------------------------
+		//  dataProvider
+		//----------------------------------    
+		
+		/**
+		 *  @private
+		 *  Storage property for dataProvider.
+		 */
+		private var _dataProvider:IList;
+		
+		/**
+		 *  @copy spark.components.DataGroup#dataProvider
+		 *
+		 *  @see #itemRenderer
+		 *  @see #itemRendererFunction
+		 *  @see mx.collections.IList
+		 *  @see mx.collections.ArrayCollection
+		 *  @see mx.collections.ArrayList
+		 *  @see mx.collections.XMLListCollection
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		[Bindable("dataProviderChanged")]
+		[Bindable("change")]
+		
+		public function get dataProvider():IList
+		{       
+			return (contentGroup) 
+			? contentGroup.dataProvider 
+				: dataGroupProperties.dataProvider;
+		}
+		
+		public function set dataProvider(value:IList):void
+		{
+			if( _dataProvider == value ) return;
+			
+			if( _dataProvider ) _dataProvider.removeEventListener( CollectionEvent.COLLECTION_CHANGE, onDataProviderCollectionChange, false );
+			
+			_dataProvider = value;
+			
+			if (contentGroup)
+			{
+				contentGroup.dataProvider = value;
+				dataGroupProperties = BitFlagUtil.update(dataGroupProperties as uint, 
+					DATA_PROVIDER_PROPERTY_FLAG, true);
+			}
+			else
+				dataGroupProperties.dataProvider = value;
+			
+			if( _dataProvider ) _dataProvider.addEventListener( CollectionEvent.COLLECTION_CHANGE, onDataProviderCollectionChange, false, 0, true );
+			
+			dispatchEvent( new Event( "dataProviderChanged" ) );
+			if( hasEventListener( CollectionEvent.COLLECTION_CHANGE )  ) dispatchEvent( new CollectionEvent( CollectionEvent.COLLECTION_CHANGE, false, false, CollectionEventKind.RESET, -1, -1, toArray() ) );
+		}
+		
+		//----------------------------------
+		//  itemRenderer
+		//----------------------------------
+		
+		/**
+		 *  @copy spark.components.DataGroup#itemRenderer
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get itemRenderer():IFactory
+		{
+			return (contentGroup) 
+			? contentGroup.itemRenderer 
+				: dataGroupProperties.itemRenderer;
+		}
+		
+		/**
+		 *  @private
+		 */
+		public function set itemRenderer(value:IFactory):void
+		{
+			if( value == itemRenderer ) return;
+			
+			if (contentGroup)
+			{
+				contentGroup.itemRenderer = value;
+				dataGroupProperties = BitFlagUtil.update(dataGroupProperties as uint, 
+					ITEM_RENDERER_PROPERTY_FLAG, true);
+			}
+			else
+				dataGroupProperties.itemRenderer = value;
+		}
+		
+		//----------------------------------
+		//  itemRendererFunction
+		//----------------------------------
+		
+		/**
+		 *  @copy spark.components.DataGroup#itemRendererFunction
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get itemRendererFunction():Function
+		{
+			return (contentGroup) 
+			? contentGroup.itemRendererFunction 
+				: dataGroupProperties.itemRendererFunction;
+		}
+		
+		/**
+		 *  @private
+		 */
+		public function set itemRendererFunction(value:Function):void
+		{
+			if (contentGroup)
+			{
+				contentGroup.itemRendererFunction = value;
+				dataGroupProperties = BitFlagUtil.update(dataGroupProperties as uint, 
+					ITEM_RENDERER_FUNCTION_PROPERTY_FLAG, true);
+			}
+			else
+				dataGroupProperties.itemRendererFunction = value;
+		}
+		
+		//----------------------------------
+		//  layout
+		//----------------------------------
+		
+		/**
+		 *  @copy spark.components.supportClasses.GroupBase#layout
+		 *
+		 *  @default VerticalLayout
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */     
+		public function get layout():LayoutBase
+		{
+			return (contentGroup) 
+			? contentGroup.layout 
+				: dataGroupProperties.layout;
+		}
+		/**
+		 *  @private
+		 */
+		public function set layout(value:LayoutBase):void
+		{
+			var layout:LayoutBase = layout;
+			
+			if( layout == value ) return;
+			
+			if( value && useVirtualLayout) value.useVirtualLayout = true;
+			
+			removeLayoutListeners();
+			
+			if( value is INavigatorLayout )
+			{
+				if (contentGroup)
+				{
+					contentGroup.layout = value;
+					dataGroupProperties = BitFlagUtil.update(dataGroupProperties as uint, 
+						LAYOUT_PROPERTY_FLAG, true);
+				}
+				else
+				{
+					dataGroupProperties.layout = value;
+				}
+				
+				addLayoutListeners();
+			}
+			else
+			{
+				throw new Error( "Layout must implement INavigatorLayout" );
+			}
+		}
+		
+		//----------------------------------
+		//  typicalItem
+		//----------------------------------
+		
+		/**
+		 *  @copy spark.components.DataGroup#typicalItem
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get typicalItem():Object
+		{
+			return (contentGroup) 
+			? contentGroup.typicalItem 
+				: dataGroupProperties.typicalItem;
+		}
+		
+		/**
+		 *  @private
+		 */
+		public function set typicalItem(value:Object):void
+		{
+			if (contentGroup)
+			{
+				contentGroup.typicalItem = value;
+				dataGroupProperties = BitFlagUtil.update(dataGroupProperties as uint, 
+					TYPICAL_ITEM_PROPERTY_FLAG, true);
+			}
+			else
+				dataGroupProperties.typicalItem = value;
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @copy ws.tink.spark.controls.DataNavigatorGroup#addItem
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function addItem( item:Object ):void
+		{
+			addItemAt( item, length );
+		}
+		
+		/**
+		 *  @copy ws.tink.spark.controls.DataNavigatorGroup#addItemAt
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function addItemAt( item:Object, index:int ):void
+		{
+			if( !dataProvider ) dataProvider = new ArrayList();
+			dataProvider.addItemAt( item, index );
+		}
+		
+		/**
+		 *  @copy ws.tink.spark.controls.DataNavigatorGroup#getItemAt
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function getItemAt( index:int, prefetch:int = 0 ):Object
+		{
+			if( !dataProvider || length <= index ) return null;
+			return  dataProvider.getItemAt( index );
+		}
+		
+		/**
+		 *  @copy ws.tink.spark.controls.DataNavigatorGroup#getItemIndex
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function getItemIndex( item:Object ):int
+		{
+			if( !dataProvider ) return -1;
+			return dataProvider.getItemIndex( item );
+		}
+		
+		/**
+		 *  @copy ws.tink.spark.controls.DataNavigatorGroup#itemUpdated
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function itemUpdated( item:Object, property:Object=null, oldValue:Object=null, newValue:Object=null ):void
+		{
+			if( dataProvider ) dataProvider.itemUpdated( item, property, oldValue, newValue );
+		}
+		
+		/**
+		 *  @copy ws.tink.spark.controls.DataNavigatorGroup#removeAll
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function removeAll():void
+		{
+			if( !dataProvider ) return;
+			dataProvider.removeAll();
+		}
+		
+		/**
+		 *  @copy ws.tink.spark.controls.DataNavigatorGroup#removeItemAt
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function removeItemAt( index:int ):Object
+		{
+			if( !dataProvider || index >= length ) return null;
+			return dataProvider.removeItemAt( index );
+		}
+		
+		/**
+		 *  @copy ws.tink.spark.controls.DataNavigatorGroup#setItemAt
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function setItemAt(item:Object, index:int):Object
+		{
+			if( !dataProvider || index > length ) return null;
+			return dataProvider.setItemAt( item, index );
+		}
+		
+		/**
+		 *  @copy ws.tink.spark.controls.DataNavigatorGroup#toArray
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function toArray():Array
+		{
+			return ( !dataProvider ) ? null : dataProvider.toArray();
+		}
+		
+		/**
+		 *  From the specified data item, return the String representation 
+		 *  of the data item for an item renderer to display.
+		 *  This method uses the <code>toString()</code> method of 
+		 *  the data item to convert it to a String representation.
+		 *  A Null data item returns an empty string.
+		 *
+		 *  @param item The data item.
+		 *
+		 *  @return The String representation of the data item.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function itemToLabel(item:Object):String
+		{
+			return LabelUtil.itemToLabel( item, labelField, labelFunction );
+		}
+		
+		/**
+		 *  Updates an item renderer for use or reuse. 
+		 *  When an item renderer is first created,
+		 *  or when it is recycled because of virtualization, this 
+		 *  SkinnableDataContainer instance can set the 
+		 *  item renderer's <code>label</code> property and 
+		 *  <code>owner</code> property. 
+		 *  
+		 *  @param renderer The renderer being updated 
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 * 
+		 */
+		public function updateRenderer(renderer:IVisualElement, itemIndex:int, data:Object):void
+		{
+			// set the owner
+			renderer.owner = this;
+			
+			// Set the index
+			if (renderer is IItemRenderer)
+				IItemRenderer(renderer).itemIndex = itemIndex;
+			
+			// set the label to the toString() of the data 
+			if (renderer is IItemRenderer)
+				IItemRenderer(renderer).label = itemToLabel(data);
+			
+			// always set the data last
+			if ((renderer is IDataRenderer) && (renderer !== data))
+				IDataRenderer(renderer).data = data;
+		}
+		
+		/**
+		 *  Adjusts the selected index to account for items being added to or 
+		 *  removed from this component.
+		 *
+		 *  @param newIndex The new index.
+		 *   
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		protected function adjustSelection( newIndex:int ):void
+		{
+			var nl:INavigatorLayout = INavigatorLayout( layout );
+			if( !nl ) return;
+			
+			if( nl is AnimationNavigatorLayoutBase )
+			{
+				var anl:AnimationNavigatorLayoutBase = AnimationNavigatorLayoutBase( nl );
+				var duration:Number = anl.duration;
+				anl.duration = 0;
+			}
+			
+			nl.selectedIndex = newIndex;
+			
+			if( anl ) anl.duration = duration;
+		}
+		
+		/**
+		 *  @private
+		 */
+		private function addLayoutListeners():void
+		{
+			if( !layout ) return;
+			layout.addEventListener( IndexChangeEvent.CHANGE, onLayoutEvent, false, 0, true );
+			layout.addEventListener( FlexEvent.VALUE_COMMIT, onLayoutEvent, false, 0, true );
+		}
+		
+		/**
+		 *  @private
+		 */
+		private function removeLayoutListeners():void
+		{
+			if( !layout ) return;
+			layout.removeEventListener( IndexChangeEvent.CHANGE, onLayoutEvent, false );
+			layout.removeEventListener( FlexEvent.VALUE_COMMIT, onLayoutEvent, false );
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden Methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 */
+		override protected function partAdded(partName:String, instance:Object):void
+		{
+			super.partAdded(partName, instance);
+			
+			if (instance == contentGroup)
+			{
+				// copy proxied values from dataGroupProperties (if set) to contentGroup
+				
+				var newDataGroupProperties:uint = 0;
+				
+				if (dataGroupProperties.layout !== undefined)
+				{
+					contentGroup.layout = dataGroupProperties.layout;
+					newDataGroupProperties = BitFlagUtil.update(newDataGroupProperties as uint, 
+						LAYOUT_PROPERTY_FLAG, true);;
+				}
+				
+				if (dataGroupProperties.autoLayout !== undefined)
+				{
+					contentGroup.autoLayout = dataGroupProperties.autoLayout;
+					newDataGroupProperties = BitFlagUtil.update(newDataGroupProperties as uint, 
+						AUTO_LAYOUT_PROPERTY_FLAG, true);
+				}
+				
+				if (dataGroupProperties.dataProvider !== undefined)
+				{
+					contentGroup.dataProvider = dataGroupProperties.dataProvider;
+					newDataGroupProperties = BitFlagUtil.update(newDataGroupProperties as uint, 
+						DATA_PROVIDER_PROPERTY_FLAG, true);
+				}
+				
+				if (dataGroupProperties.itemRenderer !== undefined)
+				{
+					contentGroup.itemRenderer = dataGroupProperties.itemRenderer;
+					newDataGroupProperties = BitFlagUtil.update(newDataGroupProperties as uint, 
+						ITEM_RENDERER_PROPERTY_FLAG, true);
+				}
+				
+				if (dataGroupProperties.itemRendererFunction !== undefined)
+				{
+					contentGroup.itemRendererFunction = dataGroupProperties.itemRendererFunction;
+					newDataGroupProperties = BitFlagUtil.update(newDataGroupProperties as uint, 
+						ITEM_RENDERER_FUNCTION_PROPERTY_FLAG, true);
+				}
+				
+				if (dataGroupProperties.typicalItem !== undefined)
+				{
+					contentGroup.typicalItem = dataGroupProperties.typicalItem;
+					newDataGroupProperties = BitFlagUtil.update(newDataGroupProperties as uint, 
+						TYPICAL_ITEM_PROPERTY_FLAG, true);
+				}
+				
+				if (dataGroupProperties.selectedIndex !== undefined)
+				{
+					contentGroup.selectedIndex = dataGroupProperties.selectedIndex;
+					newDataGroupProperties = BitFlagUtil.update(newDataGroupProperties as uint, 
+						SELECTED_INDEX_PROPERTY_FLAG, true);
+				}
+								
+				dataGroupProperties = newDataGroupProperties;
+				
+				// Register our instance as the contentGroup's item renderer update delegate.
+				contentGroup.rendererUpdateDelegate = this;
+				
+				// Not your typical delegation, see 'set useVirtualLayout'
+				if( contentGroup.layout ) contentGroup.layout.useVirtualLayout = _useVirtualLayout;
+				
+				// The only reason we have these listeners is to re-dispatch events.  
+				// We only add as necessary.
+				
+				if (hasEventListener(RendererExistenceEvent.RENDERER_ADD))
+				{
+					contentGroup.addEventListener(
+						RendererExistenceEvent.RENDERER_ADD, dispatchEvent);
+				}
+				
+				if (hasEventListener(RendererExistenceEvent.RENDERER_REMOVE))
+				{
+					contentGroup.addEventListener(
+						RendererExistenceEvent.RENDERER_REMOVE, dispatchEvent);
+				}
+			}
+		}
+		
+		/**
+		 * @private
+		 */
+		override protected function partRemoved(partName:String, instance:Object):void
+		{
+			super.partRemoved(partName, instance);
+			
+			if (instance == contentGroup)
+			{
+				contentGroup.removeEventListener(
+					RendererExistenceEvent.RENDERER_ADD, dispatchEvent);
+				contentGroup.removeEventListener(
+					RendererExistenceEvent.RENDERER_REMOVE, dispatchEvent);
+				
+				// copy proxied values from contentGroup (if explicitly set) to dataGroupProperties
+				
+				var newDataGroupProperties:Object = {};
+				
+				if (BitFlagUtil.isSet(dataGroupProperties as uint, LAYOUT_PROPERTY_FLAG))
+					newDataGroupProperties.layout = contentGroup.layout;
+				
+				if (BitFlagUtil.isSet(dataGroupProperties as uint, AUTO_LAYOUT_PROPERTY_FLAG))
+					newDataGroupProperties.autoLayout = contentGroup.autoLayout;
+				
+				if (BitFlagUtil.isSet(dataGroupProperties as uint, DATA_PROVIDER_PROPERTY_FLAG))
+					newDataGroupProperties.dataProvider = contentGroup.dataProvider;
+				
+				if (BitFlagUtil.isSet(dataGroupProperties as uint, ITEM_RENDERER_PROPERTY_FLAG))
+					newDataGroupProperties.itemRenderer = contentGroup.itemRenderer;
+				
+				if (BitFlagUtil.isSet(dataGroupProperties as uint, ITEM_RENDERER_FUNCTION_PROPERTY_FLAG))
+					newDataGroupProperties.itemRendererFunction = contentGroup.itemRendererFunction;
+				
+				if (BitFlagUtil.isSet(dataGroupProperties as uint, TYPICAL_ITEM_PROPERTY_FLAG))
+					newDataGroupProperties.typicalItem = contentGroup.typicalItem;
+				
+				if (BitFlagUtil.isSet(dataGroupProperties as uint, SELECTED_INDEX_PROPERTY_FLAG))
+					newDataGroupProperties.selectedIndex = contentGroup.selectedIndex;
+				
+				dataGroupProperties = newDataGroupProperties;
+				
+				contentGroup.dataProvider = null;
+				contentGroup.layout = null;
+				contentGroup.rendererUpdateDelegate = null;
+			}
+		}
+		
+		override protected function commitProperties():void
+		{
+			super.commitProperties();
+			
+			if( _labelFieldOrFunctionChanged )
+			{
+				// Cycle through all instantiated renderers to push the correct text 
+				// in to the renderer by setting its label property
+				if( contentGroup )
+				{
+					var itemIndex:int;
+					
+					// if virtual layout, only loop through the indices in view
+					// otherwise, loop through all of the item renderers
+					if( layout && layout.useVirtualLayout )
+					{
+						for each( itemIndex in contentGroup.getItemIndicesInView() )
+						{
+							updateRendererLabelProperty( itemIndex );
+						}
+					}
+					else
+					{
+						var n:int = contentGroup.numElements;
+						for( itemIndex = 0; itemIndex < n; itemIndex++)
+						{
+							updateRendererLabelProperty(itemIndex);
+						}
+					}
+				}
+				
+				_labelFieldOrFunctionChanged = false; 
+			}
+		}
+		
+		/**
+		 *  @private
+		 */
+		private function updateRendererLabelProperty(itemIndex:int):void
+		{
+			// grab the renderer at that index and re-compute it's label property
+			var renderer:IItemRenderer = contentGroup.getElementAt( itemIndex ) as IItemRenderer; 
+			if( renderer ) renderer.label = itemToLabel( renderer.data ); 
+		}
+		
+		/**
+		 *  @private
+		 * 
+		 *  This method is overridden so we can figure out when someone starts listening
+		 *  for property change events.  If no one's listening for them, then we don't 
+		 *  listen for them on our contentGroup.
+		 */
+		override public function addEventListener(
+			type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false) : void
+		{
+			super.addEventListener(type, listener, useCapture, priority, useWeakReference);
+			
+			// TODO (rfrishbe): this isn't ideal as we should deal with the useCapture, 
+			// priority, and useWeakReference parameters.
+			
+			// if it's a different type of event or the contentGroup doesn't
+			// exist, don't worry about it.  When the contentGroup, 
+			// gets created up, we'll check to see whether we need to add this 
+			// event listener to the contentGroup.
+			
+			if (type == RendererExistenceEvent.RENDERER_ADD && contentGroup)
+			{
+				contentGroup.addEventListener(
+					RendererExistenceEvent.RENDERER_ADD, dispatchEvent);
+			}
+			
+			if (type == RendererExistenceEvent.RENDERER_REMOVE && contentGroup)
+			{
+				contentGroup.addEventListener(
+					RendererExistenceEvent.RENDERER_REMOVE, dispatchEvent);
+			}
+		}
+		
+		/**
+		 *  @private
+		 * 
+		 *  This method is overridden so we can figure out when someone stops listening
+		 *  for property change events.  If no one's listening for them, then we don't 
+		 *  listen for them on our contentGroup.
+		 */
+		override public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false) : void
+		{
+			super.removeEventListener(type, listener, useCapture);
+			
+			// if no one's listening to us for this event any more, let's 
+			// remove our underlying event listener from the contentGroup.
+			if (type == RendererExistenceEvent.RENDERER_ADD && contentGroup)
+			{
+				if (!hasEventListener(RendererExistenceEvent.RENDERER_ADD))
+				{
+					contentGroup.removeEventListener(
+						RendererExistenceEvent.RENDERER_ADD, dispatchEvent);
+				}
+			}
+			
+			if (type == RendererExistenceEvent.RENDERER_REMOVE && contentGroup)
+			{
+				if (!hasEventListener(RendererExistenceEvent.RENDERER_REMOVE))
+				{
+					contentGroup.removeEventListener(
+						RendererExistenceEvent.RENDERER_REMOVE, dispatchEvent);
+				}
+			}
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Event Listeners.
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 */
+		private function onLayoutEvent( event:Event ):void
+		{
+			if( hasEventListener( event.type ) ) dispatchEvent( event );
+		}
+		
+		/**
+		 *  @private
+		 */
+		private function onDataProviderCollectionChange( event:CollectionEvent ):void
+		{
+			// If there is a contentGroup it will take care of adjusting the selection
+			if( !contentGroup )
+			{
+				if( event is CollectionEvent )
+				{
+					var ce:CollectionEvent = CollectionEvent( event );
+					switch( ce.kind )
+					{
+						case CollectionEventKind.ADD :
+						{
+							if( ce.location <= selectedIndex ) adjustSelection( selectedIndex + 1 );
+							break;
+						}
+						case CollectionEventKind.REMOVE :
+						{
+							if( ce.location <= selectedIndex )
+							{
+								adjustSelection( length ? selectedIndex == 0 ? 0 : selectedIndex - 1 : -1 );
+							}
+							break;
+						}
+						case CollectionEventKind.RESET :
+						{
+							adjustSelection( length ? 0 : -1 );
+							break;
+						}
+						case CollectionEventKind.MOVE :
+						{
+							if( ce.oldLocation == selectedIndex ) adjustSelection( ce.location );
+							break;
+						}
+					}
+				}
+			}
+			
+			if( hasEventListener( event.type ) ) dispatchEvent( event );
+		}
+	}
+}
\ No newline at end of file

Added: incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/DataNavigatorGroup.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/DataNavigatorGroup.as?rev=1228400&view=auto
==============================================================================
--- incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/DataNavigatorGroup.as (added)
+++ incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/DataNavigatorGroup.as Fri Jan  6 20:58:43 2012
@@ -0,0 +1,680 @@
+/*
+Copyright (c) 2010 Tink Ltd - http://www.tink.ws
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
+the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
+THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+package ws.tink.spark.controls
+{
+	import flash.events.Event;
+	
+	import mx.collections.ArrayList;
+	import mx.collections.IList;
+	import mx.core.ISelectableList;
+	import mx.core.mx_internal;
+	import mx.events.CollectionEvent;
+	import mx.events.CollectionEventKind;
+	import mx.events.FlexEvent;
+	
+	import spark.components.DataGroup;
+	import spark.events.IndexChangeEvent;
+	import spark.layouts.supportClasses.LayoutBase;
+	
+	import ws.tink.spark.layouts.StackLayout;
+	import ws.tink.spark.layouts.supportClasses.AnimationNavigatorLayoutBase;
+	import ws.tink.spark.layouts.supportClasses.INavigatorLayout;
+	
+	use namespace mx_internal;
+
+	//--------------------------------------
+	//  Events
+	//--------------------------------------
+	
+	/**
+	 *  Dispatched when the ISelectableList has been updated in some way.
+	 *
+	 *  @eventType mx.events.CollectionEvent.COLLECTION_CHANGE
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 9
+	 *  @playerversion AIR 1.1
+	 *  @productversion Flex 3
+	 */
+	[Event(name="collectionChange", type="mx.events.CollectionEvent")]
+	
+	/**
+	 *  Dispatched after the selection has changed. 
+	 *  This event is dispatched when the user interacts with the control.
+	 * 
+	 *  <p>When you change the value of the <code>selectedIndex</code> 
+	 *  or <code>selectedItem</code> properties programmatically, 
+	 *  the control does not dispatch the <code>change</code> event. 
+	 *  It dispatches the <code>valueCommit</code> event instead.</p>
+	 *
+	 *  @eventType spark.events.IndexChangeEvent.CHANGE
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	[Event(name="change", type="spark.events.IndexChangeEvent")]
+	
+	
+	/**
+	 *  The DataNavigatorGroup class is the base control class for navigating data items.
+	 * 
+	 *  The DataNavigatorGroup class converts data items to visual elements for display.
+ 	 *  While this container can hold visual elements, it is often used only 
+	 *  to hold data items as children.
+	 *
+	 *  <p>The DataNavigatorGroup class takes as children data items or visual elements 
+	 *  that implement the IVisualElement interface and are DisplayObjects.  
+	 *  Data items can be simple data items such String and Number objects, 
+	 *  and more complicated data items such as Object and XMLNode objects. 
+	 *  While these containers can hold visual elements, 
+	 *  they are often used only to hold data items as children.</p>
+	 *
+	 *  <p>An item renderer defines the visual representation of the 
+	 *  data item in the container. 
+	 *  The item renderer converts the data item into a format that can 
+	 *  be displayed by the container. 
+	 *  You must pass an item renderer to a DataGroup container to render 
+	 *  data items appropriately.</p>
+	 *
+	 *  <p>The layout for a NavigatorGroup must implement INavigatorLayout.</p>
+	 * 
+	 *  <p>To improve performance and minimize application size, 
+	 *  the DataNavigatorGroup container cannot be skinned. 
+	 *  If you want to apply a skin, use the DataNavigator instead.</p>
+	 *  
+	 *  <p>The DataGroup container has the following default characteristics:</p>
+	 *  <table class="innertable">
+	 *     <tr><th>Characteristic</th><th>Description</th></tr>
+	 *     <tr><td>Default size</td><td>Large enough to display its children</td></tr>
+	 *     <tr><td>Minimum size</td><td>0 pixels</td></tr>
+	 *     <tr><td>Maximum size</td><td>10000 pixels wide and 10000 pixels high</td></tr>
+	 *  </table>
+	 *
+	 *  @mxml <p>The <code>&lt;st:DataNavigatorGroup&gt;</code> tag inherits all of the tag 
+	 *  attributes of its superclass and adds the following tag attributes:</p>
+	 *
+	 *  <pre>
+	 *  &lt;st:DataNavigatorGroup
+	 *
+	 *    <strong>Properties</strong>
+	 *    selectedIndex="-1"
+	 *    selectedItem="undefined"
+	 *    length="0"
+	 * 
+	 *    <strong>Events</strong>
+	 *    change="<i>No default</i>"
+	 *    collectionChange="<i>No default</i>"
+	 *  /&gt;
+	 *  </pre>
+	 *  
+	 *  @see ws.tink.spark.controls.DataNavigator
+	 *  @see ws.tink.spark.containers.NavigatorGroup
+	 *  @see spark.skins.spark.DefaultItemRenderer
+	 *  @see spark.skins.spark.DefaultComplexItemRenderer
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	public class DataNavigatorGroup extends DataGroup implements ISelectableList
+	{
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constructor. 
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */  
+		public function DataNavigatorGroup()
+		{
+			super();
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Properties
+		//
+		//--------------------------------------------------------------------------
+		
+		//----------------------------------
+		//  selectedIndex
+		//---------------------------------- 
+		
+		/**
+		 *  @private
+		 *  Storage property for selectedIndex.
+		 */
+		private var _selectedIndex		: int = -1;
+		
+		[Bindable("change")]
+		[Bindable("valueCommit")]
+		
+		/**
+		 *  The index of the currently selected item IList item.
+		 *  Setting this property deselects the currently selected 
+		 *  index and selects the newly specified item.
+		 *  
+		 *  @default -1
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function set selectedIndex( value:int ):void
+		{
+			if( _selectedIndex == value ) return;
+			
+			_selectedIndex = value;
+
+			if( layout ) INavigatorLayout( layout ).selectedIndex = _selectedIndex;
+		}
+		/**
+		 *  @private
+		 */
+		public function get selectedIndex():int
+		{
+			return ( layout ) ? INavigatorLayout( layout ).selectedIndex : _selectedIndex;
+		}
+		
+		
+		//----------------------------------
+		//  selectedItem
+		//---------------------------------- 
+		
+		[Bindable("change")]
+		[Bindable("valueCommit")]
+		
+		/**
+		 *  The item that is currently selected. 
+		 *  Setting this property deselects the currently selected 
+		 *  item and selects the newly specified item.
+		 *
+		 *  @default undefined
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get selectedItem():Object
+		{
+			var index:int = selectedIndex;
+			return index != -1 ? dataProvider.getItemAt( index ) : null;
+		}
+		/**
+		 *  @private
+		 */
+		public function set selectedItem( value:Object ):void
+		{
+			if( dataProvider )
+			{
+				var index:int = dataProvider.getItemIndex( value );
+				if( index != -1 ) selectedIndex = index;
+			}
+		}
+		
+		
+		//----------------------------------
+		//  length
+		//---------------------------------- 
+		
+		/**
+		 *  The number of items in this collection. 
+		 *  0 means no items while -1 means the length is unknown. 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get length():int
+		{
+			return dataProvider ? dataProvider.length : 0;
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden Properties
+		//
+		//--------------------------------------------------------------------------
+		
+		//----------------------------------
+		//  layout
+		//----------------------------------    
+		
+		/**
+		 *  @private
+		 */
+		override public function set layout( value:LayoutBase ):void
+		{
+			if( layout == value ) return;
+			
+			if( value is INavigatorLayout )
+			{
+				removeLayoutListeners();
+				INavigatorLayout( value ).selectedIndex = _selectedIndex;
+				super.layout = value;
+				addLayoutListeners();
+			}
+			else
+			{
+				throw new Error( "Layout must implement INavigatorLayout" );
+			}
+			
+		}
+		
+		
+		//----------------------------------
+		//  dataProvider
+		//----------------------------------  
+		
+		[Bindable("change")]
+		
+		/**
+		 *  @private
+		 */
+		override public function set dataProvider( value:IList ):void
+		{
+			super.dataProvider = value;
+			
+			if( hasEventListener( CollectionEvent.COLLECTION_CHANGE )  ) dispatchEvent( new CollectionEvent( CollectionEvent.COLLECTION_CHANGE, false, false, CollectionEventKind.RESET, -1, -1, toArray() ) );
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Adds the specified item to the end of the list.
+		 *  Equivalent to <code>addItemAt(item, length)</code>.
+		 *
+		 *  @param item The item to add.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function addItem( item:Object ):void
+		{
+			addItemAt( item, length );
+		}
+		
+		/**
+		 *  Adds the item at the specified index.  
+		 *  The index of any item greater than the index of the added item is increased by one.  
+		 *  If the the specified index is less than zero or greater than the length
+		 *  of the list, a RangeError is thrown.
+		 * 
+		 *  @param item The item to place at the index.
+		 *
+		 *  @param index The index at which to place the item.
+		 *
+		 *  @throws RangeError if index is less than 0 or greater than the length of the list. 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function addItemAt( item:Object, index:int ):void
+		{
+			if( !dataProvider ) dataProvider = new ArrayList();
+			dataProvider.addItemAt( item, index );
+		}
+		
+		/**
+		 *  Gets the item at the specified index.
+		 * 
+		 *  @param index The index in the list from which to retrieve the item.
+		 *
+		 *  @param prefetch An <code>int</code> indicating both the direction
+		 *  and number of items to fetch during the request if the item is
+		 *  not local.
+		 *
+		 *  @return The item at that index, or <code>null</code> if there is none.
+		 *
+		 *  @throws mx.collections.errors.ItemPendingError if the data for that index needs to be 
+		 *  loaded from a remote location.
+		 *
+		 *  @throws RangeError if <code>index &lt; 0</code>
+		 *  or <code>index >= length</code>.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function getItemAt( index:int, prefetch:int = 0 ):Object
+		{
+			if( length <= index ) return null;
+			return  dataProvider.getItemAt( index );
+		}
+		
+		/**
+		 *  Returns the index of the item if it is in the list such that
+		 *  getItemAt(index) == item.
+		 * 
+		 *  <p>Note: unlike <code>IViewCursor.find<i>xxx</i>()</code> methods,
+		 *  The <code>getItemIndex()</code> method cannot take a parameter with 
+		 *  only a subset of the fields in the item being serched for; 
+		 *  this method always searches for an item that exactly matches
+		 *  the input parameter.</p>
+		 * 
+		 *  @param item The item to find.
+		 *
+		 *  @return The index of the item, or -1 if the item is not in the list.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function getItemIndex( item:Object ):int
+		{
+			if( !dataProvider ) return -1;
+			return dataProvider.getItemIndex( item );
+		}
+		
+		/**
+		 *  Notifies the view that an item has been updated.  
+		 *  This is useful if the contents of the view do not implement 
+		 *  <code>IEventDispatcher</code> and dispatches a 
+		 *  <code>PropertyChangeEvent</code>.  
+		 *  If a property is specified the view may be able to optimize its 
+		 *  notification mechanism.
+		 *  Otherwise it may choose to simply refresh the whole view.
+		 *
+		 *  @param item The item within the view that was updated.
+		 *
+		 *  @param property The name of the property that was updated.
+		 *
+		 *  @param oldValue The old value of that property. (If property was null,
+		 *  this can be the old value of the item.)
+		 *
+		 *  @param newValue The new value of that property. (If property was null,
+		 *  there's no need to specify this as the item is assumed to be
+		 *  the new value.)
+		 *
+		 *  @see mx.events.CollectionEvent
+		 *  @see mx.events.PropertyChangeEvent
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function itemUpdated( item:Object, property:Object=null, oldValue:Object=null, newValue:Object=null ):void
+		{
+			if( dataProvider ) dataProvider.itemUpdated( item, property, oldValue, newValue );
+		}
+		
+		/** 
+		 *  Removes all items from the list.
+		 *
+		 *  <p>If any item is not local and an asynchronous operation must be
+		 *  performed, an <code>ItemPendingError</code> will be thrown.</p>
+		 *
+		 *  <p>See the ItemPendingError documentation as well as
+		 *  the collections documentation for more information
+		 *   on using the <code>ItemPendingError</code>.</p>
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function removeAll():void
+		{
+			if( !dataProvider ) return;
+			dataProvider.removeAll();
+		}
+		
+		/**
+		 *  Removes the item at the specified index and returns it.  
+		 *  Any items that were after this index are now one index earlier.
+		 *
+		 *  @param index The index from which to remove the item.
+		 *
+		 *  @return The item that was removed.
+		 *
+		 *  @throws RangeError is index is less than 0 or greater than length. 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function removeItemAt( index:int ):Object
+		{
+			if( !dataProvider || index >= numElements ) return null;
+			return dataProvider.removeItemAt( index );
+		}
+		
+		/**
+		 *  Places the item at the specified index.  
+		 *  If an item was already at that index the new item will replace it
+		 *  and it will be returned.
+		 *
+		 *  @param item The new item to be placed at the specified index.
+		 *
+		 *  @param index The index at which to place the item.
+		 *
+		 *  @return The item that was replaced, or <code>null</code> if none.
+		 *
+		 *  @throws RangeError if index is less than 0 or greater than length.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function setItemAt(item:Object, index:int):Object
+		{
+			if( !dataProvider || index > numElements ) return null;
+			return dataProvider.setItemAt( item, index );
+		}
+		
+		/**
+		 *  Returns an Array that is populated in the same order as the IList
+		 *  implementation.
+		 *  This method can throw an ItemPendingError.
+		 *
+		 *  @return The array.
+		 *  
+		 *  @throws mx.collections.errors.ItemPendingError If the data is not yet completely loaded
+		 *  from a remote location.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function toArray():Array
+		{
+			return ( !dataProvider ) ? null : dataProvider.toArray();
+		}
+		
+		
+		/**
+		 *  Adjusts the selected index to account for items being added to or 
+		 *  removed from this component.
+		 *
+		 *  @param newIndex The new index.
+		 *   
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		protected function adjustSelection( newIndex:int ):void
+		{	
+			if( layout is AnimationNavigatorLayoutBase )
+			{
+				const anl:AnimationNavigatorLayoutBase = AnimationNavigatorLayoutBase( layout );
+				const duration:Number = anl.duration;
+				anl.duration = 0;
+			}
+			
+			selectedIndex = newIndex;
+			
+			if( anl ) anl.duration = duration;
+		}
+		
+		
+		/**
+		 *  @private
+		 */
+		private function addLayoutListeners():void
+		{
+			if( !layout ) return;
+			layout.addEventListener( IndexChangeEvent.CHANGE, onLayoutEvent, false, 0, true );
+			layout.addEventListener( FlexEvent.VALUE_COMMIT, onLayoutEvent, false, 0, true );
+		}
+		
+		/**
+		 *  @private
+		 */
+		private function removeLayoutListeners():void
+		{
+			if( !layout ) return;
+			layout.removeEventListener( IndexChangeEvent.CHANGE, onLayoutEvent, false );
+			layout.removeEventListener( FlexEvent.VALUE_COMMIT, onLayoutEvent, false );
+		}
+		
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden Methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @inheritDoc
+		 *  
+		 *  <p>If the layout object has not been set yet, 
+		 *  createChildren() assigns this container a 
+		 *  default layout object, BasicLayout.</p>
+		 */ 
+		override protected function createChildren():void
+		{
+			if( !layout ) layout = new StackLayout();
+			if( _selectedIndex != -1 ) INavigatorLayout( layout ).selectedIndex = _selectedIndex;
+			
+			super.createChildren();
+		}
+		
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Event Listeners
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 */
+		private function onLayoutEvent( event:Event ):void
+		{
+			_selectedIndex = INavigatorLayout( layout ).selectedIndex;
+			if( hasEventListener( event.type ) ) dispatchEvent( event );
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden Event Listeners
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 *  Called when contents within the dataProvider changes.
+		 *	Re-dispatch the event if we have a listener.
+		 *
+		 *  @param event The collection change event
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override mx_internal function dataProvider_collectionChangeHandler( event:CollectionEvent ):void
+		{
+			super.dataProvider_collectionChangeHandler( event );
+			
+			if( event is CollectionEvent )
+			{
+				var ce:CollectionEvent = CollectionEvent( event );
+				switch( ce.kind )
+				{
+					case CollectionEventKind.ADD :
+					{
+						if( ce.location <= selectedIndex ) adjustSelection( selectedIndex + 1 );
+						break;
+					}
+					case CollectionEventKind.REMOVE :
+					{
+						if( ce.location <= selectedIndex ) adjustSelection( length ? selectedIndex == 0 ? 0 : selectedIndex - 1 : -1 );
+						break;
+					}
+					case CollectionEventKind.RESET :
+					{
+						adjustSelection( length ? 0 : -1 );
+						break;
+					}
+					case CollectionEventKind.MOVE :
+					{
+						if( ce.oldLocation == selectedIndex ) adjustSelection( ce.location );
+						break;
+					}
+				}
+			}
+			
+			if( hasEventListener( event.type ) ) dispatchEvent( event );
+		}
+	}
+}
\ No newline at end of file

Added: incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/supportClasses/AnimationTarget.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/supportClasses/AnimationTarget.as?rev=1228400&view=auto
==============================================================================
--- incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/supportClasses/AnimationTarget.as (added)
+++ incubator/flex/whiteboard/navigators/src/ws/tink/spark/controls/supportClasses/AnimationTarget.as Fri Jan  6 20:58:43 2012
@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2010 Tink Ltd - http://www.tink.ws
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
+the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
+THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+package ws.tink.spark.controls.supportClasses
+{
+	import spark.effects.animation.Animation;
+	import spark.effects.animation.IAnimationTarget;
+	
+	public class AnimationTarget implements IAnimationTarget
+	{
+		public var updateFunction:Function;
+		public var startFunction:Function;
+		public var stopFunction:Function;
+		public var endFunction:Function;
+		public var repeatFunction:Function;
+		
+		public function AnimationTarget(updateFunction:Function = null)
+		{
+			this.updateFunction = updateFunction;
+		}
+		
+		public function animationStart(animation:Animation):void
+		{
+			if (startFunction != null)
+				startFunction(animation);
+		}
+		
+		public function animationEnd(animation:Animation):void
+		{
+			if (endFunction != null)
+				endFunction(animation);
+		}
+		
+		public function animationStop(animation:Animation):void
+		{
+			if (stopFunction != null)
+				stopFunction(animation);
+		}
+		
+		public function animationRepeat(animation:Animation):void
+		{
+			if (repeatFunction != null)
+				repeatFunction(animation);
+		}
+		
+		public function animationUpdate(animation:Animation):void
+		{
+			if (updateFunction != null)
+				updateFunction(animation);
+		}
+		
+	}
+}