| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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.managers |
| { |
| import flash.display.Stage; |
| import flash.events.Event; |
| import flash.events.EventDispatcher; |
| |
| import mx.core.UIComponentGlobals; |
| import mx.core.mx_internal; |
| import mx.events.DynamicEvent; |
| import mx.events.FlexEvent; |
| import mx.managers.layoutClasses.PriorityQueue; |
| |
| CONFIG::performanceInstrumentation |
| { |
| import mx.utils.PerfUtil; |
| } |
| |
| use namespace mx_internal; |
| |
| /** |
| * The LayoutManager is the engine behind |
| * Flex's measurement and layout strategy. |
| * Layout is performed in three phases; commit, measurement, and layout. |
| * |
| * <p>Each phase is distinct from the others and all UIComponents of |
| * one phase are processed prior to moving on to the next phase. |
| * During the processing of UIComponents in a phase, requests for |
| * UIComponents to get re-processed by some phase may occur. |
| * These requests are queued and are only processed |
| * during the next run of the phase.</p> |
| * |
| * <p>The <b>commit</b> phase begins with a call to |
| * <code>validateProperties()</code>, which walks through a list |
| * (reverse sorted by nesting level) of objects calling each object's |
| * <a href="../core/UIComponent.html#validateProperties()"> |
| * <code>validateProperties()</code></a>method.</p> |
| * |
| * <p>The objects in the list are processed in reversed nesting order, |
| * with the <b>least</b> deeply nested object accessed first. |
| * This can also be referred to as top-down or outside-in ordering.</p> |
| * |
| * <p>This phase allows components whose contents depend on property |
| * settings to configure themselves prior to the measurement |
| * and the layout phases. |
| * For the sake of performance, sometimes a component's property setter |
| * method does not do all the work to update to the new property value. |
| * Instead, the property setter calls the <code>invalidateProperties()</code> |
| * method, deferring the work until this phase runs. |
| * This prevents unnecessary work if the property is set multiple times.</p> |
| * |
| * <p>The <b>measurement</b> phase begins with a call to |
| * <code>validateSize()</code>, which walks through a list |
| * (sorted by nesting level) of objects calling each object's |
| * <a href="../core/UIComponent.html#validateSize()"><code>validateSize()</code></a> |
| * method to determine if the object has changed in size.</p> |
| * |
| * <p>If an object's <a href="../core/UIComponent.html#invalidateSize()"> |
| * <code>invalidateSize()</code></a> method was previously called, |
| * then the <code>validateSize()</code> method is called. |
| * If the size or position of the object was changed as a result of the |
| * <code>validateSize()</code> call, then the object's |
| * <a href="../core/UIComponent.html#invalidateDisplayList()"> |
| * <code>invalidateDisplayList()</code></a> method is called, thus adding |
| * the object to the processing queue for the next run of the layout phase. |
| * Additionally, the object's parent is marked for both measurement |
| * and layout phases, by calling |
| * <a href="../core/UIComponent.html#invalidateSize()"> |
| * <code>invalidateSize()</code></a> and |
| * <a href="../core/UIComponent.html#invalidateDisplayList()"> |
| * <code>invalidateDisplayList()</code></a> respectively.</p> |
| * |
| * <p>The objects in the list are processed by nesting order, |
| * with the <b>most</b> deeply nested object accessed first. |
| * This can also be referred to as bottom-up inside-out ordering.</p> |
| * |
| * <p>The <b>layout</b> phase begins with a call to the |
| * <code>validateDisplayList()</code> method, which walks through a list |
| * (reverse sorted by nesting level) of objects calling each object's |
| * <a href="../core/UIComponent.html#validateDisplayList()"> |
| * <code>validateDisplayList()</code></a> method to request the object to size |
| * and position all components contained within it (i.e. its children).</p> |
| * |
| * <p>If an object's <a href="../core/UIComponent.html#invalidateDisplayList()"> |
| * <code>invalidateDisplayList()</code></a> method was previously called, |
| * then <code>validateDisplayList()</code> method for the object is called.</p> |
| * |
| * <p>The objects in the list are processed in reversed nesting order, |
| * with the <b>least</b> deeply nested object accessed first. |
| * This can also be referred to as top-down or outside-in ordering.</p> |
| * |
| * <p>In general, components do not override the <code>validateProperties()</code>, |
| * <code>validateSize()</code>, or <code>validateDisplayList()</code> methods. |
| * In the case of UIComponents, most components override the |
| * <code>commitProperties()</code>, <code>measure()</code>, or |
| * <code>updateDisplayList()</code> methods, which are called |
| * by the <code>validateProperties()</code>, |
| * <code>validateSize()</code>, or |
| * <code>validateDisplayList()</code> methods, respectively.</p> |
| * |
| * <p>At application startup, a single instance of the LayoutManager is created |
| * and stored in the <code>UIComponent.layoutManager</code> property. |
| * All components are expected to use that instance. |
| * If you do not have access to the UIComponent object, |
| * you can also access the LayoutManager using the static |
| * <code>LayoutManager.getInstance()</code> method.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public class LayoutManager extends EventDispatcher implements ILayoutManager |
| { |
| include "../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * The sole instance of this singleton class. |
| */ |
| private static var instance:LayoutManager; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Returns the sole instance of this singleton class, |
| * creating it if it does not already exist. |
| * |
| * @return Returns the sole instance of this singleton class, |
| * creating it if it does not already exist. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public static function getInstance():LayoutManager |
| { |
| if (!instance) |
| instance = new LayoutManager(); |
| |
| return instance; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| * @private |
| */ |
| public function LayoutManager() |
| { |
| super(); |
| |
| systemManager = SystemManagerGlobals.topLevelSystemManagers[0]; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * A queue of objects that need to dispatch updateComplete events |
| * when invalidation processing is complete |
| */ |
| private var updateCompleteQueue:PriorityQueue = new PriorityQueue(); |
| |
| /** |
| * @private |
| * A queue of objects to be processed during the first phase |
| * of invalidation processing, when an ILayoutManagerClient has |
| * its validateProperties() method called (which in a UIComponent |
| * calls commitProperties()). |
| * Objects are added to this queue by invalidateProperties() |
| * and removed by validateProperties(). |
| */ |
| private var invalidatePropertiesQueue:PriorityQueue = new PriorityQueue(); |
| |
| /** |
| * @private |
| * A flag indicating whether there are objects |
| * in the invalidatePropertiesQueue. |
| * It is set true by invalidateProperties() |
| * and set false by validateProperties(). |
| */ |
| private var invalidatePropertiesFlag:Boolean = false; |
| |
| // flag when in validateClient to check the properties queue again |
| private var invalidateClientPropertiesFlag:Boolean = false; |
| |
| /** |
| * @private |
| * A queue of objects to be processed during the second phase |
| * of invalidation processing, when an ILayoutManagerClient has |
| * its validateSize() method called (which in a UIComponent |
| * calls measure()). |
| * Objects are added to this queue by invalidateSize(). |
| * and removed by validateSize(). |
| */ |
| private var invalidateSizeQueue:PriorityQueue = new PriorityQueue(); |
| |
| /** |
| * @private |
| * A flag indicating whether there are objects |
| * in the invalidateSizeQueue. |
| * It is set true by invalidateSize() |
| * and set false by validateSize(). |
| */ |
| private var invalidateSizeFlag:Boolean = false; |
| |
| // flag when in validateClient to check the size queue again |
| private var invalidateClientSizeFlag:Boolean = false; |
| |
| /** |
| * @private |
| * A queue of objects to be processed during the third phase |
| * of invalidation processing, when an ILayoutManagerClient has |
| * its validateDisplayList() method called (which in a |
| * UIComponent calls updateDisplayList()). |
| * Objects are added to this queue by invalidateDisplayList() |
| * and removed by validateDisplayList(). |
| */ |
| private var invalidateDisplayListQueue:PriorityQueue = new PriorityQueue(); |
| |
| /** |
| * @private |
| * A flag indicating whether there are objects |
| * in the invalidateDisplayListQueue. |
| * It is set true by invalidateDisplayList() |
| * and set false by validateDisplayList(). |
| */ |
| private var invalidateDisplayListFlag:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| private var waitedAFrame:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| private var listenersAttached:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| private var originalFrameRate:Number; |
| |
| /** |
| * @private |
| * used in validateClient to quickly estimate whether we have to |
| * search the queues again |
| */ |
| private var targetLevel:int = int.MAX_VALUE; |
| |
| /** |
| * @private |
| * the top level systemmanager |
| */ |
| private var systemManager:ISystemManager; |
| |
| /** |
| * @private |
| * the current object being validated |
| * it could be wrong if the validating object calls validateNow on something. |
| */ |
| private var currentObject:ILayoutManagerClient; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // usePhasedInstantiation |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the usePhasedInstantiation property. |
| */ |
| private var _usePhasedInstantiation:Boolean = false; |
| |
| /** |
| * A flag that indicates whether the LayoutManager allows screen updates |
| * between phases. |
| * If <code>true</code>, measurement and layout are done in phases, one phase |
| * per screen update. |
| * All components have their <code>validateProperties()</code> |
| * and <code>commitProperties()</code> methods |
| * called until all their properties are validated. |
| * The screen will then be updated. |
| * |
| * <p>Then all components will have their <code>validateSize()</code> |
| * and <code>measure()</code> |
| * methods called until all components have been measured, then the screen |
| * will be updated again. </p> |
| * |
| * <p>Finally, all components will have their |
| * <code>validateDisplayList()</code> and |
| * <code>updateDisplayList()</code> methods called until all components |
| * have been validated, and the screen will be updated again. |
| * If in the validation of one phase, an earlier phase gets invalidated, |
| * the LayoutManager starts over. |
| * This is more efficient when large numbers of components |
| * are being created an initialized. The framework is responsible for setting |
| * this property.</p> |
| * |
| * <p>If <code>false</code>, all three phases are completed before the screen is updated.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get usePhasedInstantiation():Boolean |
| { |
| return _usePhasedInstantiation; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set usePhasedInstantiation(value:Boolean):void |
| { |
| if (_usePhasedInstantiation != value) |
| { |
| _usePhasedInstantiation = value; |
| |
| // While we're doing phased instantiation, temporarily increase |
| // the frame rate. That will cause the enterFrame and render |
| // events to fire more promptly, which improves performance. |
| try { |
| // can't use FlexGlobals here. It may not be setup yet |
| var stage:Stage = systemManager.stage; |
| if (stage) |
| { |
| if (value) |
| { |
| originalFrameRate = stage.frameRate; |
| stage.frameRate = 1000; |
| } |
| else |
| { |
| stage.frameRate = originalFrameRate; |
| } |
| } |
| } |
| catch (e:SecurityError) |
| { |
| // trace("ignoring security error changing the framerate " + e); |
| } |
| } |
| } |
| |
| //---------------------------------- |
| // debugHelper |
| //---------------------------------- |
| |
| /* |
| // LAYOUT_DEBUG |
| import mx.managers.layoutClasses.LayoutDebugHelper; |
| private static var _layoutDebugHelper:LayoutDebugHelper; |
| |
| public static function get debugHelper():LayoutDebugHelper |
| { |
| if (!_layoutDebugHelper) |
| { |
| _layoutDebugHelper = new LayoutDebugHelper(); |
| _layoutDebugHelper.mouseEnabled = false; |
| var sm:ISystemManager = SystemManagerGlobals.topLevelSystemManagers[0] |
| sm.addChild(_layoutDebugHelper); |
| } |
| return _layoutDebugHelper; |
| } */ |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods: Invalidation |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Adds an object to the list of components that want their |
| * <code>validateProperties()</code> method called. |
| * A component should call this method when a property changes. |
| * Typically, a property setter method |
| * stores a the new value in a temporary variable and calls |
| * the <code>invalidateProperties()</code> method |
| * so that its <code>validateProperties()</code> |
| * and <code>commitProperties()</code> methods are called |
| * later, when the new value will actually be applied to the component and/or |
| * its children. The advantage of this strategy is that often, more than one |
| * property is changed at a time and the properties may interact with each |
| * other, or repeat some code as they are applied, or need to be applied in |
| * a specific order. This strategy allows the most efficient method of |
| * applying new property values. |
| * |
| * @param obj The object whose property changed. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function invalidateProperties(obj:ILayoutManagerClient ):void |
| { |
| if (!invalidatePropertiesFlag && systemManager) |
| { |
| invalidatePropertiesFlag = true; |
| |
| if (!listenersAttached) |
| attachListeners(systemManager); |
| } |
| |
| // trace("LayoutManager adding " + Object(obj) + " to invalidatePropertiesQueue"); |
| |
| if (targetLevel <= obj.nestLevel) |
| invalidateClientPropertiesFlag = true; |
| |
| invalidatePropertiesQueue.addObject(obj, obj.nestLevel); |
| |
| // trace("LayoutManager added " + Object(obj) + " to invalidatePropertiesQueue"); |
| } |
| |
| /** |
| * Adds an object to the list of components that want their |
| * <code>validateSize()</code> method called. |
| * Called when an object's size changes. |
| * |
| * <p>An object's size can change for two reasons:</p> |
| * |
| * <ol> |
| * <li>The content of the object changes. For example, the size of a |
| * button changes when its <code>label</code> is changed.</li> |
| * <li>A script explicitly changes one of the following properties: |
| * <code>minWidth</code>, <code>minHeight</code>, |
| * <code>explicitWidth</code>, <code>explicitHeight</code>, |
| * <code>maxWidth</code>, or <code>maxHeight</code>.</li> |
| * </ol> |
| * |
| * <p>When the first condition occurs, it's necessary to recalculate |
| * the measurements for the object. |
| * When the second occurs, it's not necessary to recalculate the |
| * measurements because the new size of the object is known. |
| * However, it's necessary to remeasure and relayout the object's |
| * parent.</p> |
| * |
| * @param obj The object whose size changed. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function invalidateSize(obj:ILayoutManagerClient ):void |
| { |
| if (!invalidateSizeFlag && systemManager) |
| { |
| invalidateSizeFlag = true; |
| |
| if (!listenersAttached) |
| { |
| attachListeners(systemManager); |
| } |
| } |
| |
| // trace("LayoutManager adding " + Object(obj) + " to invalidateSizeQueue"); |
| |
| if (targetLevel <= obj.nestLevel) |
| invalidateClientSizeFlag = true; |
| |
| invalidateSizeQueue.addObject(obj, obj.nestLevel); |
| |
| // trace("LayoutManager added " + Object(obj) + " to invalidateSizeQueue"); |
| } |
| |
| /** |
| * Called when a component changes in some way that its layout and/or visuals |
| * need to be changed. |
| * In that case, it is necessary to run the component's layout algorithm, |
| * even if the component's size hasn't changed. For example, when a new child component |
| * is added, or a style property changes or the component has been given |
| * a new size by its parent. |
| * |
| * @param obj The object that changed. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function invalidateDisplayList(obj:ILayoutManagerClient ):void |
| { |
| if (!invalidateDisplayListFlag && systemManager) |
| { |
| invalidateDisplayListFlag = true; |
| |
| if (!listenersAttached) |
| { |
| attachListeners(systemManager); |
| } |
| } |
| else if (!invalidateDisplayListFlag && !systemManager) |
| { |
| // trace("systemManager is null"); |
| } |
| |
| // trace("LayoutManager adding " + Object(obj) + " to invalidateDisplayListQueue"); |
| |
| invalidateDisplayListQueue.addObject(obj, obj.nestLevel); |
| |
| // trace("LayoutManager added " + Object(obj) + " to invalidateDisplayListQueue"); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods: Commitment, measurement, layout, and drawing |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Validates all components whose properties have changed and have called |
| * the <code>invalidateProperties()</code> method. |
| * It calls the <code>validateProperties()</code> method on those components |
| * and will call <code>validateProperties()</code> on any other components that are |
| * invalidated while validating other components. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| private function validateProperties():void |
| { |
| // trace("--- LayoutManager: validateProperties --->"); |
| CONFIG::performanceInstrumentation |
| { |
| var perfUtil:PerfUtil = PerfUtil.getInstance(); |
| perfUtil.markTime("validateProperties().start"); |
| } |
| |
| // Keep traversing the invalidatePropertiesQueue until we've reached the end. |
| // More elements may get added to the queue while we're in this loop, or a |
| // a recursive call to this function may remove elements from the queue while |
| // we're in this loop. |
| var obj:ILayoutManagerClient = ILayoutManagerClient(invalidatePropertiesQueue.removeSmallest()); |
| while (obj) |
| { |
| // trace("LayoutManager calling validateProperties() on " + Object(obj) + " " + DisplayObject(obj).width + " " + DisplayObject(obj).height); |
| |
| CONFIG::performanceInstrumentation |
| { |
| var token:int = perfUtil.markStart(); |
| } |
| |
| if (obj.nestLevel) |
| { |
| currentObject = obj; |
| obj.validateProperties(); |
| if (!obj.updateCompletePendingFlag) |
| { |
| updateCompleteQueue.addObject(obj, obj.nestLevel); |
| obj.updateCompletePendingFlag = true; |
| } |
| } |
| CONFIG::performanceInstrumentation |
| { |
| perfUtil.markEnd(".validateProperties()", token, 2 /*tolerance*/, obj); |
| } |
| |
| // Once we start, don't stop. |
| obj = ILayoutManagerClient(invalidatePropertiesQueue.removeSmallest()); |
| } |
| |
| if (invalidatePropertiesQueue.isEmpty()) |
| { |
| // trace("Properties Queue is empty"); |
| |
| invalidatePropertiesFlag = false; |
| } |
| |
| // trace("<--- LayoutManager: validateProperties ---"); |
| CONFIG::performanceInstrumentation |
| { |
| perfUtil.markTime("validateProperties().end"); |
| } |
| } |
| |
| /** |
| * Validates all components whose properties have changed and have called |
| * the <code>invalidateSize()</code> method. |
| * It calls the <code>validateSize()</code> method on those components |
| * and will call the <code>validateSize()</code> method |
| * on any other components that are |
| * invalidated while validating other components. |
| * The </code>validateSize()</code> method starts with |
| * the most deeply nested child in the tree of display objects |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| private function validateSize():void |
| { |
| // trace("--- LayoutManager: validateSize --->"); |
| CONFIG::performanceInstrumentation |
| { |
| var perfUtil:PerfUtil = PerfUtil.getInstance(); |
| perfUtil.markTime("validateSize().start"); |
| } |
| |
| var obj:ILayoutManagerClient = ILayoutManagerClient(invalidateSizeQueue.removeLargest()); |
| while (obj) |
| { |
| // trace("LayoutManager calling validateSize() on " + Object(obj)); |
| CONFIG::performanceInstrumentation |
| { |
| var objToken:int; |
| if (PerfUtil.detailedSampling) |
| objToken = perfUtil.markStart(); |
| } |
| |
| if (obj.nestLevel) |
| { |
| currentObject = obj; |
| obj.validateSize(); |
| if (!obj.updateCompletePendingFlag) |
| { |
| updateCompleteQueue.addObject(obj, obj.nestLevel); |
| obj.updateCompletePendingFlag = true; |
| } |
| } |
| |
| CONFIG::performanceInstrumentation |
| { |
| if (PerfUtil.detailedSampling) |
| perfUtil.markEnd(".validateSize()", objToken, 2 /*tolerance*/, obj); |
| } |
| // trace("LayoutManager validateSize: " + Object(obj) + " " + IFlexDisplayObject(obj).measuredWidth + " " + IFlexDisplayObject(obj).measuredHeight); |
| |
| obj = ILayoutManagerClient(invalidateSizeQueue.removeLargest()); |
| } |
| |
| if (invalidateSizeQueue.isEmpty()) |
| { |
| // trace("Measurement Queue is empty"); |
| |
| invalidateSizeFlag = false; |
| } |
| |
| CONFIG::performanceInstrumentation |
| { |
| perfUtil.markTime("validateSize().end"); |
| } |
| // trace("<--- LayoutManager: validateSize ---"); |
| } |
| |
| /** |
| * Validates all components whose properties have changed and have called |
| * the <code>invalidateDisplayList()</code> method. |
| * It calls <code>validateDisplayList()</code> method on those components |
| * and will call the <code>validateDisplayList()</code> method |
| * on any other components that are |
| * invalidated while validating other components. |
| * The <code>validateDisplayList()</code> method starts with |
| * the least deeply nested child in the tree of display objects |
| * |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| private function validateDisplayList():void |
| { |
| // trace("--- LayoutManager: validateDisplayList --->"); |
| CONFIG::performanceInstrumentation |
| { |
| var perfUtil:PerfUtil = PerfUtil.getInstance(); |
| perfUtil.markTime("validateDisplayList().start"); |
| } |
| |
| var obj:ILayoutManagerClient = ILayoutManagerClient(invalidateDisplayListQueue.removeSmallest()); |
| while (obj) |
| { |
| // trace("LayoutManager calling validateDisplayList on " + Object(obj) + " " + DisplayObject(obj).width + " " + DisplayObject(obj).height); |
| CONFIG::performanceInstrumentation |
| { |
| var objToken:int; |
| if (PerfUtil.detailedSampling) |
| objToken = perfUtil.markStart(); |
| } |
| |
| if (obj.nestLevel) |
| { |
| currentObject = obj; |
| obj.validateDisplayList(); |
| if (!obj.updateCompletePendingFlag) |
| { |
| updateCompleteQueue.addObject(obj, obj.nestLevel); |
| obj.updateCompletePendingFlag = true; |
| } |
| } |
| // trace("LayoutManager return from validateDisplayList on " + Object(obj) + " " + DisplayObject(obj).width + " " + DisplayObject(obj).height); |
| |
| CONFIG::performanceInstrumentation |
| { |
| if (PerfUtil.detailedSampling) |
| perfUtil.markEnd(".validateDisplayList()", objToken, 2 /*tolerance*/, obj); |
| } |
| |
| // Once we start, don't stop. |
| obj = ILayoutManagerClient(invalidateDisplayListQueue.removeSmallest()); |
| } |
| |
| |
| if (invalidateDisplayListQueue.isEmpty()) |
| { |
| // trace("Layout Queue is empty"); |
| |
| invalidateDisplayListFlag = false; |
| } |
| |
| CONFIG::performanceInstrumentation |
| { |
| perfUtil.markTime("validateDisplayList().end"); |
| } |
| // trace("<--- LayoutManager: validateDisplayList ---"); |
| } |
| |
| /** |
| * @private |
| */ |
| private function doPhasedInstantiation():void |
| { |
| // trace(">>DoPhasedInstantiation"); |
| |
| // If phasing, do only one phase: validateProperties(), |
| // validateSize(), or validateDisplayList(). |
| if (usePhasedInstantiation) |
| { |
| if (invalidatePropertiesFlag) |
| { |
| validateProperties(); |
| |
| // The Preloader listens for this event. |
| systemManager.document.dispatchEvent( |
| new Event("validatePropertiesComplete")); |
| } |
| |
| else if (invalidateSizeFlag) |
| { |
| validateSize(); |
| |
| // The Preloader listens for this event. |
| systemManager.document.dispatchEvent( |
| new Event("validateSizeComplete")); |
| } |
| |
| else if (invalidateDisplayListFlag) |
| { |
| validateDisplayList(); |
| |
| // The Preloader listens for this event. |
| systemManager.document.dispatchEvent( |
| new Event("validateDisplayListComplete")); |
| } |
| } |
| |
| // Otherwise, do one pass of all three phases. |
| else |
| { |
| if (invalidatePropertiesFlag) |
| validateProperties(); |
| |
| if (invalidateSizeFlag) |
| validateSize(); |
| |
| if (invalidateDisplayListFlag) |
| validateDisplayList(); |
| } |
| |
| // trace("invalidatePropertiesFlag " + invalidatePropertiesFlag); |
| // trace("invalidateSizeFlag " + invalidateSizeFlag); |
| // trace("invalidateDisplayListFlag " + invalidateDisplayListFlag); |
| |
| if (invalidatePropertiesFlag || |
| invalidateSizeFlag || |
| invalidateDisplayListFlag) |
| { |
| attachListeners(systemManager); |
| } |
| else |
| { |
| usePhasedInstantiation = false; |
| |
| listenersAttached = false; |
| |
| var obj:ILayoutManagerClient = ILayoutManagerClient(updateCompleteQueue.removeLargest()); |
| while (obj) |
| { |
| if(obj.nestLevel) |
| { |
| if (!obj.initialized && obj.processedDescriptors) |
| obj.initialized = true; |
| if (obj.hasEventListener(FlexEvent.UPDATE_COMPLETE)) |
| obj.dispatchEvent(new FlexEvent(FlexEvent.UPDATE_COMPLETE)); |
| } |
| |
| obj.updateCompletePendingFlag = false; |
| obj = ILayoutManagerClient(updateCompleteQueue.removeLargest()); |
| } |
| |
| // trace("updateComplete"); |
| |
| dispatchEvent(new FlexEvent(FlexEvent.UPDATE_COMPLETE)); |
| } |
| |
| // trace("<<DoPhasedInstantation"); |
| } |
| |
| /** |
| * When properties are changed, components generally do not apply those changes immediately. |
| * Instead the components usually call one of the LayoutManager's invalidate methods and |
| * apply the properties at a later time. The actual property you set can be read back |
| * immediately, but if the property affects other properties in the component or its |
| * children or parents, those other properties may not be immediately updated. To |
| * guarantee that the values are updated, you can call the <code>validateNow()</code> method. |
| * It updates all properties in all components before returning. |
| * Call this method only when necessary as it is a computationally intensive call. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function validateNow():void |
| { |
| if (!usePhasedInstantiation) |
| { |
| var infiniteLoopGuard:int = 0; |
| while (listenersAttached && infiniteLoopGuard++ < 100) |
| doPhasedInstantiation(); |
| } |
| } |
| |
| /** |
| * When properties are changed, components generally do not apply those changes immediately. |
| * Instead the components usually call one of the LayoutManager's invalidate methods and |
| * apply the properties at a later time. The actual property you set can be read back |
| * immediately, but if the property affects other properties in the component or its |
| * children or parents, those other properties may not be immediately updated. |
| * |
| * <p>To guarantee that the values are updated, |
| * you can call the <code>validateClient()</code> method. |
| * It updates all properties in all components whose nest level is greater than or equal |
| * to the target component before returning. |
| * Call this method only when necessary as it is a computationally intensive call.</p> |
| * |
| * @param target The component passed in is used to test which components |
| * should be validated. All components contained by this component will have their |
| * <code>validateProperties()</code>, <code>commitProperties()</code>, |
| * <code>validateSize()</code>, <code>measure()</code>, |
| * <code>validateDisplayList()</code>, |
| * and <code>updateDisplayList()</code> methods called. |
| * |
| * @param skipDisplayList If <code>true</code>, |
| * does not call the <code>validateDisplayList()</code> |
| * and <code>updateDisplayList()</code> methods. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function validateClient(target:ILayoutManagerClient, skipDisplayList:Boolean = false):void |
| { |
| CONFIG::performanceInstrumentation |
| { |
| var perfUtil:PerfUtil = PerfUtil.getInstance(); |
| var token:int = perfUtil.markStart(); |
| } |
| |
| var lastCurrentObject:ILayoutManagerClient = currentObject; |
| |
| var obj:ILayoutManagerClient; |
| var done:Boolean = false; |
| var oldTargetLevel:int = targetLevel; |
| |
| // the theory here is that most things that get validated are deep in the tree |
| // and so there won't be nested calls to validateClient. However if there is, |
| // we don't want to have a more sophisticated scheme of keeping track |
| // of dirty flags at each level that is being validated, but we definitely |
| // do not want to keep scanning the queues unless we're pretty sure that |
| // something might be dirty so we just say that if something got dirty |
| // during this call at a deeper nesting than the first call to validateClient |
| // then we'll scan the queues. So we only change targetLevel if we're the |
| // outer call to validateClient and only that call restores it. |
| if (targetLevel == int.MAX_VALUE) |
| targetLevel = target.nestLevel; |
| |
| // trace("--- LayoutManager: validateClient ---> target = " + target); |
| |
| while (!done) |
| { |
| // assume we won't find anything |
| done = true; |
| |
| // Keep traversing the invalidatePropertiesQueue until we've reached the end. |
| // More elements may get added to the queue while we're in this loop, or a |
| // a recursive call to this function may remove elements from the queue while |
| // we're in this loop. |
| obj = ILayoutManagerClient(invalidatePropertiesQueue.removeSmallestChild(target)); |
| while (obj) |
| { |
| // trace("LayoutManager calling validateProperties() on " + Object(obj) + " " + DisplayObject(obj).width + " " + DisplayObject(obj).height); |
| |
| if (obj.nestLevel) |
| { |
| currentObject = obj; |
| obj.validateProperties(); |
| if (!obj.updateCompletePendingFlag) |
| { |
| updateCompleteQueue.addObject(obj, obj.nestLevel); |
| obj.updateCompletePendingFlag = true; |
| } |
| } |
| |
| // Once we start, don't stop. |
| obj = ILayoutManagerClient(invalidatePropertiesQueue.removeSmallestChild(target)); |
| } |
| |
| if (invalidatePropertiesQueue.isEmpty()) |
| { |
| // trace("Properties Queue is empty"); |
| |
| invalidatePropertiesFlag = false; |
| invalidateClientPropertiesFlag = false; |
| } |
| |
| // trace("--- LayoutManager: validateSize --->"); |
| |
| obj = ILayoutManagerClient(invalidateSizeQueue.removeLargestChild(target)); |
| while (obj) |
| { |
| // trace("LayoutManager calling validateSize() on " + Object(obj)); |
| |
| if (obj.nestLevel) |
| { |
| currentObject = obj; |
| obj.validateSize(); |
| if (!obj.updateCompletePendingFlag) |
| { |
| updateCompleteQueue.addObject(obj, obj.nestLevel); |
| obj.updateCompletePendingFlag = true; |
| } |
| } |
| |
| // trace("LayoutManager validateSize: " + Object(obj) + " " + IFlexDisplayObject(obj).measuredWidth + " " + IFlexDisplayObject(obj).measuredHeight); |
| |
| if (invalidateClientPropertiesFlag) |
| { |
| // did any properties get invalidated while validating size? |
| obj = ILayoutManagerClient(invalidatePropertiesQueue.removeSmallestChild(target)); |
| if (obj) |
| { |
| // re-queue it. we'll pull it at the beginning of the loop |
| invalidatePropertiesQueue.addObject(obj, obj.nestLevel); |
| done = false; |
| break; |
| } |
| } |
| |
| obj = ILayoutManagerClient(invalidateSizeQueue.removeLargestChild(target)); |
| } |
| |
| if (invalidateSizeQueue.isEmpty()) |
| { |
| // trace("Measurement Queue is empty"); |
| |
| invalidateSizeFlag = false; |
| invalidateClientSizeFlag = false; |
| } |
| |
| if (!skipDisplayList) |
| { |
| // trace("--- LayoutManager: validateDisplayList --->"); |
| |
| obj = ILayoutManagerClient(invalidateDisplayListQueue.removeSmallestChild(target)); |
| while (obj) |
| { |
| // trace("LayoutManager calling validateDisplayList on " + Object(obj) + " " + DisplayObject(obj).width + " " + DisplayObject(obj).height); |
| |
| if (obj.nestLevel) |
| { |
| currentObject = obj; |
| obj.validateDisplayList(); |
| if (!obj.updateCompletePendingFlag) |
| { |
| updateCompleteQueue.addObject(obj, obj.nestLevel); |
| obj.updateCompletePendingFlag = true; |
| } |
| } |
| // trace("LayoutManager return from validateDisplayList on " + Object(obj) + " " + DisplayObject(obj).width + " " + DisplayObject(obj).height); |
| |
| if (invalidateClientPropertiesFlag) |
| { |
| // did any properties get invalidated while validating size? |
| obj = ILayoutManagerClient(invalidatePropertiesQueue.removeSmallestChild(target)); |
| if (obj) |
| { |
| // re-queue it. we'll pull it at the beginning of the loop |
| invalidatePropertiesQueue.addObject(obj, obj.nestLevel); |
| done = false; |
| break; |
| } |
| } |
| |
| if (invalidateClientSizeFlag) |
| { |
| obj = ILayoutManagerClient(invalidateSizeQueue.removeLargestChild(target)); |
| if (obj) |
| { |
| // re-queue it. we'll pull it at the beginning of the loop |
| invalidateSizeQueue.addObject(obj, obj.nestLevel); |
| done = false; |
| break; |
| } |
| } |
| |
| // Once we start, don't stop. |
| obj = ILayoutManagerClient(invalidateDisplayListQueue.removeSmallestChild(target)); |
| } |
| |
| |
| if (invalidateDisplayListQueue.isEmpty()) |
| { |
| // trace("Layout Queue is empty"); |
| |
| invalidateDisplayListFlag = false; |
| } |
| } |
| } |
| |
| if (oldTargetLevel == int.MAX_VALUE) |
| { |
| targetLevel = int.MAX_VALUE; |
| if (!skipDisplayList) |
| { |
| obj = ILayoutManagerClient(updateCompleteQueue.removeLargestChild(target)); |
| while (obj) |
| { |
| if(obj.nestLevel) |
| { |
| if (!obj.initialized) |
| obj.initialized = true; |
| |
| if (obj.hasEventListener(FlexEvent.UPDATE_COMPLETE)) |
| obj.dispatchEvent(new FlexEvent(FlexEvent.UPDATE_COMPLETE)); |
| } |
| |
| obj.updateCompletePendingFlag = false; |
| obj = ILayoutManagerClient(updateCompleteQueue.removeLargestChild(target)); |
| } |
| } |
| } |
| |
| currentObject = lastCurrentObject; |
| |
| CONFIG::performanceInstrumentation |
| { |
| perfUtil.markEnd(" validateClient()", token, 2 /*tolerance*/, target); |
| } |
| |
| // trace("<--- LayoutManager: validateClient --- target = " + target); |
| } |
| |
| /** |
| * Returns <code>true</code> if there are components that need validating; |
| * <code>false</code> if all components have been validated. |
| * |
| * @return Returns <code>true</code> if there are components that need validating; |
| * <code>false</code> if all components have been validated. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function isInvalid():Boolean |
| { |
| return invalidatePropertiesFlag || |
| invalidateSizeFlag || |
| invalidateDisplayListFlag; |
| } |
| |
| /** |
| * @private |
| * callLater() is called immediately after an object is created. |
| * We really want to wait one more frame before starting in. |
| */ |
| private function waitAFrame(event:Event):void |
| { |
| // trace(">>LayoutManager:WaitAFrame"); |
| |
| systemManager.removeEventListener(Event.ENTER_FRAME, waitAFrame); |
| systemManager.addEventListener(Event.ENTER_FRAME, doPhasedInstantiationCallback); |
| waitedAFrame = true; |
| |
| // trace("<<LayoutManager:WaitAFrame"); |
| } |
| |
| public function attachListeners(systemManager:ISystemManager):void |
| { |
| if (!waitedAFrame) |
| { |
| systemManager.addEventListener(Event.ENTER_FRAME, waitAFrame); |
| } |
| else |
| { |
| systemManager.addEventListener(Event.ENTER_FRAME, doPhasedInstantiationCallback); |
| if (!usePhasedInstantiation) |
| { |
| if (systemManager && (systemManager.stage || usingBridge(systemManager))) |
| { |
| systemManager.addEventListener(Event.RENDER, doPhasedInstantiationCallback); |
| if (systemManager.stage) |
| systemManager.stage.invalidate(); |
| } |
| } |
| } |
| |
| listenersAttached = true; |
| } |
| |
| private function doPhasedInstantiationCallback(event:Event):void |
| { |
| // if our background processing is suspended, then we shouldn't do any |
| // validation |
| if (UIComponentGlobals.callLaterSuspendCount > 0) |
| return; |
| |
| systemManager.removeEventListener(Event.ENTER_FRAME, doPhasedInstantiationCallback); |
| systemManager.removeEventListener(Event.RENDER, doPhasedInstantiationCallback); |
| |
| if (!UIComponentGlobals.catchCallLaterExceptions) |
| { |
| doPhasedInstantiation(); |
| } |
| |
| else |
| { |
| try |
| { |
| doPhasedInstantiation(); |
| } |
| catch(e:Error) |
| { |
| // Dispatch a callLaterError dynamic event for Design View. |
| var callLaterErrorEvent:DynamicEvent = new DynamicEvent("callLaterError"); |
| callLaterErrorEvent.error = e; |
| callLaterErrorEvent.source = this; |
| callLaterErrorEvent.object = currentObject; |
| systemManager.dispatchEvent(callLaterErrorEvent); |
| } |
| } |
| currentObject = null; |
| } |
| |
| private var _usingBridge:int = -1; |
| |
| /** |
| * @private |
| */ |
| private function usingBridge(sm:ISystemManager):Boolean |
| { |
| if (_usingBridge == 0) return false; |
| if (_usingBridge == 1) return true; |
| |
| if (!sm) return false; |
| |
| // no types so no dependencies |
| var mp:Object = sm.getImplementation("mx.managers::IMarshalSystemManager"); |
| if (!mp) |
| { |
| _usingBridge = 0; |
| return false; |
| } |
| if (mp.useSWFBridge()) |
| { |
| _usingBridge = 1; |
| return true; |
| } |
| _usingBridge = 0; |
| return false; |
| } |
| |
| } |
| |
| } |
| |