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><st:DataAccordion></code> tag inherits all of the
+ * tag attributes of its superclass, and adds the following tag attributes:</p>
+ *
+ * <pre>
+ * <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>
+ * />
+ * </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><s:SkinnableDataContainer></code> tag inherits all of the tag
+ * attributes of its superclass and adds the following tag attributes:</p>
+ *
+ * <pre>
+ * <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>"
+ * />
+ * </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><st:DataNavigatorGroup></code> tag inherits all of the tag
+ * attributes of its superclass and adds the following tag attributes:</p>
+ *
+ * <pre>
+ * <st:DataNavigatorGroup
+ *
+ * <strong>Properties</strong>
+ * selectedIndex="-1"
+ * selectedItem="undefined"
+ * length="0"
+ *
+ * <strong>Events</strong>
+ * change="<i>No default</i>"
+ * collectionChange="<i>No default</i>"
+ * />
+ * </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 < 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);
+ }
+
+ }
+}