//////////////////////////////////////////////////////////////////////////////// // // 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 overrides property of the State class. * Use the creationPolicy property to specify to create the child * at application startup or when you change to a view state. * *

The child does not dispatch the creationComplete event until * it is added to a container. For example, the following code adds a * Button control as part of a view state change:

* *
 *  <mx:AddChild relativeTo="{v1}">
 *      <mx:Button id="b0" label="New Button"/>
 *  </mx:AddChild> 
* *

In the previous example, the Button control does not dispatch * the creationComplete 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 creationPolicy property is set to all, * the Button control dispatches the event at application startup. * If the creationPolicy property is set to auto, * the Button control dispatches the event when you change to the view state.

* * @mxml * *

The <mx:AddChild> tag * has the following attributes:

* *
 *  <mx:AddChild
 *  Properties
 *  target="null"
 *  targetFactory="null"
 *  creationPolicy="auto"
 *  position="lastChild"
 *  relativeTo="parent of the State object"
 *  />
 *  
* * @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 target * relative to the relativeTo 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 targetFactory will create * the instance of the child. * Flex uses this properthy only if you specify a targetFactory property. * The following values are valid: * *

* * * * * *
ValueMeaning
auto(default)Create the instance the * first time it is needed.
allCreate the instance when the * application started up.
noneDo not automatically create the instance. * You must call the createInstance() method to create * the instance.
* * @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 relativeTo property. * Valid values are "before", "after", * "firstChild", and "lastChild". * * @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 position property. * This property is optional; if * you omit it, Flex uses the immediate parent of the State * object, that is, the component that has the states * property, or <mx:states>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 targetFactory * property with a creationPolicy of "all". * *

Do not set this property if you set the targetFactory * property.

* * @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: * * *

If you set this property, the child is instantiated at the time * determined by the creationPolicy property.

* *

Do not set this property if you set the target * property. * This propety is the AddChild class default property. * Setting this property with a creationPolicy of "all" * is equivalent to setting a target property.

* * @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 targetFactory * property and a creationPolicy value of "none". * Flex automatically calls this method if the creationPolicy * property value is "auto" or "all". * 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; } } }