| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package mx.states |
| { |
| |
| import flash.display.DisplayObject; |
| import flash.display.DisplayObjectContainer; |
| import mx.core.ContainerCreationPolicy; |
| import mx.core.IDeferredInstance; |
| import mx.core.mx_internal; |
| import mx.core.UIComponent; |
| import mx.resources.IResourceManager; |
| import mx.resources.ResourceManager; |
| |
| use namespace mx_internal; |
| |
| [DefaultProperty("targetFactory")] |
| |
| [ResourceBundle("states")] |
| |
| /** |
| * The AddChild class adds a child display object, such as a component, |
| * to a container as part of a view state. |
| * You use this class in the <code>overrides</code> property of the State class. |
| * Use the <code>creationPolicy</code> property to specify to create the child |
| * at application startup or when you change to a view state. |
| * |
| * <p>The child does not dispatch the <code>creationComplete</code> event until |
| * it is added to a container. For example, the following code adds a |
| * Button control as part of a view state change:</p> |
| * |
| * <pre> |
| * <mx:AddChild relativeTo="{v1}"> |
| * <mx:Button id="b0" label="New Button"/> |
| * </mx:AddChild> </pre> |
| * |
| * <p>In the previous example, the Button control does not dispatch |
| * the <code>creationComplete</code> event until you change state and the |
| * Button control is added to a container. |
| * If the AddChild class defines both the Button and a container, such as a Canvas container, |
| * then the Button control dispatches the creationComplete event when it is created. |
| * For example, if the <code>creationPolicy</code> property is set to <code>all</code>, |
| * the Button control dispatches the event at application startup. |
| * If the <code>creationPolicy</code> property is set to <code>auto</code>, |
| * the Button control dispatches the event when you change to the view state. </p> |
| * |
| * @mxml |
| * |
| * <p>The <code><mx:AddChild></code> tag |
| * has the following attributes:</p> |
| * |
| * <pre> |
| * <mx:AddChild |
| * <b>Properties</b> |
| * target="null" |
| * targetFactory="null" |
| * creationPolicy="auto" |
| * position="lastChild" |
| * relativeTo="<i>parent of the State object</i>" |
| * /> |
| * </pre> |
| * |
| * @see mx.states.State |
| * @see mx.states.RemoveChild |
| * @see mx.states.Transition |
| * @see mx.effects.AddChildAction |
| * |
| * @includeExample examples/StatesExample.mxml |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public class AddChild extends OverrideBase |
| { |
| include "../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @param relativeTo The component relative to which child is added. |
| * |
| * @param target The child object. |
| * All Flex components are subclasses of the DisplayObject class. |
| * |
| * @param position the location in the display list of the <code>target</code> |
| * relative to the <code>relativeTo</code> component. Must be one of the following: |
| * "firstChild", "lastChild", "before" or "after". |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function AddChild(relativeTo:UIComponent = null, |
| target:DisplayObject = null, |
| position:String = "lastChild") |
| { |
| super(); |
| |
| this.relativeTo = relativeTo; |
| this.target = target; |
| this.position = position; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| mx_internal var added:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| mx_internal var instanceCreated:Boolean = false; |
| |
| /** |
| * @private |
| * Used for accessing localized Error messages. |
| */ |
| private var resourceManager:IResourceManager = |
| ResourceManager.getInstance(); |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //------------------------------------ |
| // creationPolicy |
| //------------------------------------ |
| |
| /** |
| * @private |
| * Storage for the creationPolicy property. |
| */ |
| private var _creationPolicy:String = ContainerCreationPolicy.AUTO; |
| |
| [Inspectable(category="General")] |
| |
| /** |
| * The creation policy for this child. |
| * This property determines when the <code>targetFactory</code> will create |
| * the instance of the child. |
| * Flex uses this properthy only if you specify a <code>targetFactory</code> property. |
| * The following values are valid: |
| * |
| * <p></p> |
| * <table class="innertable"> |
| * <tr><th>Value</th><th>Meaning</th></tr> |
| * <tr><td><code>auto</code></td><td>(default)Create the instance the |
| * first time it is needed.</td></tr> |
| * <tr><td><code>all</code></td><td>Create the instance when the |
| * application started up.</td></tr> |
| * <tr><td><code>none</code></td><td>Do not automatically create the instance. |
| * You must call the <code>createInstance()</code> method to create |
| * the instance.</td></tr> |
| * </table> |
| * |
| * @default "auto" |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get creationPolicy():String |
| { |
| return _creationPolicy; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set creationPolicy(value:String):void |
| { |
| _creationPolicy = value; |
| |
| if (_creationPolicy == ContainerCreationPolicy.ALL) |
| createInstance(); |
| } |
| |
| //------------------------------------ |
| // position |
| //------------------------------------ |
| |
| [Inspectable(category="General")] |
| |
| /** |
| * The position of the child in the display list, relative to the |
| * object specified by the <code>relativeTo</code> property. |
| * Valid values are <code>"before"</code>, <code>"after"</code>, |
| * <code>"firstChild"</code>, and <code>"lastChild"</code>. |
| * |
| * @default "lastChild" |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public var position:String; |
| |
| //------------------------------------ |
| // relativeTo |
| //------------------------------------ |
| |
| [Inspectable(category="General")] |
| |
| /** |
| * The object relative to which the child is added. This property is used |
| * in conjunction with the <code>position</code> property. |
| * This property is optional; if |
| * you omit it, Flex uses the immediate parent of the <code>State</code> |
| * object, that is, the component that has the <code>states</code> |
| * property, or <code><mx:states></code>tag that specifies the State |
| * object. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public var relativeTo:Object; |
| |
| //------------------------------------ |
| // target |
| //------------------------------------ |
| |
| /** |
| * @private |
| * Storage for the target property |
| */ |
| private var _target:DisplayObject; |
| |
| [Inspectable(category="General")] |
| |
| /** |
| * |
| * The child to be added. |
| * If you set this property, the child instance is created at app startup. |
| * Setting this property is equivalent to setting a <code>targetFactory</code> |
| * property with a <code>creationPolicy</code> of <code>"all"</code>. |
| * |
| * <p>Do not set this property if you set the <code>targetFactory</code> |
| * property.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get target():DisplayObject |
| { |
| if (!_target && creationPolicy != ContainerCreationPolicy.NONE) |
| createInstance(); |
| |
| return _target; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set target(value:DisplayObject):void |
| { |
| _target = value; |
| } |
| |
| //------------------------------------ |
| // targetFactory |
| //------------------------------------ |
| |
| /** |
| * @private |
| * Storage for the targetFactory property. |
| */ |
| private var _targetFactory:IDeferredInstance; |
| |
| [Inspectable(category="General")] |
| |
| /** |
| * |
| * The factory that creates the child. You can specify either of the following items: |
| * <ul> |
| * <li>A factory class that implements the IDeferredInstance |
| * interface and creates the child instance or instances. |
| * </li> |
| * <li>A Flex component, (that is, any class that is a subclass |
| * of the UIComponent class), such as the Button contol. |
| * If you use a Flex component, the Flex compiler automatically |
| * wraps the component in a factory class. |
| * </li> |
| * </ul> |
| * |
| * <p>If you set this property, the child is instantiated at the time |
| * determined by the <code>creationPolicy</code> property.</p> |
| * |
| * <p>Do not set this property if you set the <code>target</code> |
| * property. |
| * This propety is the <code>AddChild</code> class default property. |
| * Setting this property with a <code>creationPolicy</code> of "all" |
| * is equivalent to setting a <code>target</code> property.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get targetFactory():IDeferredInstance |
| { |
| return _targetFactory; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set targetFactory(value:IDeferredInstance):void |
| { |
| _targetFactory = value; |
| |
| if (creationPolicy == ContainerCreationPolicy.ALL) |
| createInstance(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Creates the child instance from the factory. |
| * You must use this method only if you specify a <code>targetFactory</code> |
| * property and a <code>creationPolicy</code> value of <code>"none"</code>. |
| * Flex automatically calls this method if the <code>creationPolicy</code> |
| * property value is <code>"auto"</code> or <code>"all"</code>. |
| * If you call this method multiple times, the child instance is |
| * created only on the first call. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function createInstance():void |
| { |
| if (!instanceCreated && !_target && targetFactory) |
| { |
| instanceCreated = true; |
| var instance:Object = targetFactory.getInstance(); |
| if (instance is DisplayObject) |
| _target = DisplayObject(instance); |
| } |
| } |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function initialize():void |
| { |
| if (creationPolicy == ContainerCreationPolicy.AUTO) |
| createInstance(); |
| } |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function apply(parent:UIComponent):void |
| { |
| var obj:* = getOverrideContext(relativeTo, parent); |
| |
| parentContext = parent; |
| added = false; |
| |
| // Early exit if child is null or not a valid container. |
| if (!target || !(obj is DisplayObjectContainer)) |
| { |
| if (relativeTo != null && !applied) |
| { |
| // Our destination context is unavailable so we attempt to register |
| // a listener on our parent document to detect when/if it becomes |
| // valid. |
| addContextListener(relativeTo); |
| } |
| applied = true; |
| return; |
| } |
| |
| applied = true; |
| relativeTo = obj; |
| |
| // Can't reparent. Must remove before adding. |
| if (target.parent) |
| { |
| var message:String = resourceManager.getString( |
| "states", "alreadyParented"); |
| throw new Error(message); |
| return; |
| } |
| |
| switch (position) |
| { |
| case "before": |
| { |
| obj.parent.addChildAt(target, |
| obj.parent.getChildIndex(obj)); |
| break; |
| } |
| |
| case "after": |
| { |
| obj.parent.addChildAt(target, |
| obj.parent.getChildIndex(obj) + 1); |
| break; |
| } |
| |
| case "firstChild": |
| { |
| obj.addChildAt(target, 0); |
| break; |
| } |
| |
| case "lastChild": |
| default: |
| { |
| obj.addChild(target); |
| break; |
| } |
| } |
| |
| added = true; |
| } |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function remove(parent:UIComponent):void |
| { |
| var obj:* = getOverrideContext(relativeTo, parent); |
| |
| if (!added || !(obj is DisplayObjectContainer)) |
| { |
| if (obj == null) |
| { |
| // It seems our override is no longer active, but we were never |
| // able to successfully apply ourselves, so remove our context |
| // listener if applicable. |
| removeContextListener(); |
| applied = false; |
| parentContext = null; |
| } |
| return; |
| } |
| |
| switch (position) |
| { |
| case "before": |
| case "after": |
| { |
| obj.parent.removeChild(target); |
| break; |
| } |
| |
| case "firstChild": |
| case "lastChild": |
| default: |
| { |
| if (obj == target.parent) |
| { |
| obj.removeChild(target); |
| } |
| break; |
| } |
| } |
| |
| // Clear our flags and override context. |
| added = false; |
| applied = false; |
| parentContext = null; |
| } |
| } |
| |
| } |