You can subscribe to this list here.
| 2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
(58) |
Dec
(4) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2005 |
Jan
(23) |
Feb
(3) |
Mar
(6) |
Apr
(4) |
May
(15) |
Jun
(22) |
Jul
(18) |
Aug
(3) |
Sep
(25) |
Oct
(7) |
Nov
(86) |
Dec
(9) |
| 2006 |
Jan
(20) |
Feb
(44) |
Mar
(59) |
Apr
(23) |
May
(37) |
Jun
(35) |
Jul
|
Aug
(2) |
Sep
(3) |
Oct
(21) |
Nov
(17) |
Dec
(22) |
| 2007 |
Jan
(13) |
Feb
(7) |
Mar
(1) |
Apr
(13) |
May
(4) |
Jun
(2) |
Jul
(5) |
Aug
(8) |
Sep
(13) |
Oct
(22) |
Nov
(3) |
Dec
|
| 2008 |
Jan
(2) |
Feb
(3) |
Mar
(1) |
Apr
(3) |
May
|
Jun
(2) |
Jul
(34) |
Aug
(10) |
Sep
(5) |
Oct
(6) |
Nov
(8) |
Dec
|
| 2009 |
Jan
(1) |
Feb
(10) |
Mar
(4) |
Apr
(12) |
May
(10) |
Jun
(27) |
Jul
|
Aug
(1) |
Sep
(3) |
Oct
|
Nov
(6) |
Dec
(1) |
| 2010 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
(2) |
Oct
|
Nov
|
Dec
|
| 2011 |
Jan
|
Feb
|
Mar
(5) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| 2017 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
From: Luke B. <lb...@gm...> - 2007-04-06 20:41:11
|
I'm not sure why you're getting that particular error, but you should be running your test cases from a TestRunner, not just instantiating them directly. Essentially, you want two application roots, one that is your deployed application, and the other that extends asunit.textui.TestRunner and calls: start(TestCaseOrTestSuite:Class, [methodName:String, traceOutput:Boolean]); Then you want MXMLC to switch between the the deployed application root or your concrete TestRunner depending on what you're doing at the moment. You should know that if you pass a methodName to the start method, the base TestCase will call setUp, then the method and stop. This gives you the ability to attach visual assets to the stage (using TestCase.addChild(child:DisplayObject)), and actually see them... Please let us know if that doesn't solve the problem. Thanks, Luke Bayes www.asunit.org On 3/31/07, Robert Stackhouse <rob...@gm...> wrote: > > Has anyone else had this problem? > > C:\SVN\AgCg\ActionScript3\Projects\ASUnitDemo\tests\ExampleTest.as(4): > col: 35 Error: The definition of base class TestCase was not found. > > I am using FlashDevelop and Ant, but I know neither is my problem as I > tried to compile by hand: > > C:\SVN\AgCg\ActionScript3\Projects\ASUnitDemo>mxmlc -sp="C:/Program > Files/AsUnit/framework/as3/asunit" > -sp=C:/SVN/AgCg/ActionScript3/Projects/ASUnitDemo/tests > -default-frame-rate=24 -default-background-color=0xFFFFFF -default-size > 550 400 -o=C:/SVN/AgCg/ActionScript3/Projects/ASUnitDemo/deploy/App.swf -- > C:/SVN/AgCg/ActionScript3/Projects/ASUnitDemo/src/App.as > > My directory structure is as follows: > > ASUnitDemo/ > -src/ > --App.as > --Example.as > -tests/ > --AllTests.as > --ExampleTest.as > > The contents of the relevant files are as follows: > > App.as > package > { > import flash.display.Sprite; > import flash.display.StageAlign; > import flash.display.StageScaleMode; > import ExampleTest; > > public class App extends Sprite > { > public function App() > { > init(); > } > > private function init():void > { > stage.scaleMode = StageScaleMode.NO_SCALE; > stage.align=StageAlign.TOP_LEFT; > var tests:ExampleTest = new ExampleTest(); > } > } > } > > Example.as > package { > > public class Example { > > public function Example() { > } > } > } > > AllTests.as > package { > import asunit.framework.TestSuite; > import ExampleTest; > > public class AllTests extends asunit.framework.TestSuite{ > > public function AllTests() { > addTest(new ExampleTest()); > } > } > } > > ExampleTest.as > package { > import asunit.framework.TestCase; > > public class ExampleTest extends TestCase { > private var instance:Example; > > public function ExampleTest(testMethod:String = null) { > super(testMethod); > } > > protected override function setUp():void { > instance = new Example(); > } > > protected override function tearDown():void { > instance = null; > } > > public function testInstantiated():void { > assertTrue("Example instantiated", instance is Example); > } > > public function test():void { > assertTrue("failing test", false); > } > } > } > > Thanks in advance for any help! > > Robert > > > > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share > your > opinions on IT & business topics through brief surveys-and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > Asunit-users mailing list > Asu...@li... > https://lists.sourceforge.net/lists/listinfo/asunit-users > > |
|
From: Robert S. <rob...@gm...> - 2007-03-31 21:54:47
|
Has anyone else had this problem?
C:\SVN\AgCg\ActionScript3\Projects\ASUnitDemo\tests\ExampleTest.as(4): col:
35 Error: The definition of base class TestCase was not found.
I am using FlashDevelop and Ant, but I know neither is my problem as I tried
to compile by hand:
C:\SVN\AgCg\ActionScript3\Projects\ASUnitDemo>mxmlc -sp="C:/Program
Files/AsUnit/framework/as3/asunit"
-sp=C:/SVN/AgCg/ActionScript3/Projects/ASUnitDemo/tests
-default-frame-rate=24 -default-background-color=0xFFFFFF -default-size 550
400 -o=C:/SVN/AgCg/ActionScript3/Projects/ASUnitDemo/deploy/App.swf --
C:/SVN/AgCg/ActionScript3/Projects/ASUnitDemo/src/App.as
My directory structure is as follows:
ASUnitDemo/
-src/
--App.as
--Example.as
-tests/
--AllTests.as
--ExampleTest.as
The contents of the relevant files are as follows:
App.as
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import ExampleTest;
public class App extends Sprite
{
public function App()
{
init();
}
private function init():void
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align=StageAlign.TOP_LEFT;
var tests:ExampleTest = new ExampleTest();
}
}
}
Example.as
package {
public class Example {
public function Example() {
}
}
}
AllTests.as
package {
import asunit.framework.TestSuite;
import ExampleTest;
public class AllTests extends asunit.framework.TestSuite{
public function AllTests() {
addTest(new ExampleTest());
}
}
}
ExampleTest.as
package {
import asunit.framework.TestCase;
public class ExampleTest extends TestCase {
private var instance:Example;
public function ExampleTest(testMethod:String = null) {
super(testMethod);
}
protected override function setUp():void {
instance = new Example();
}
protected override function tearDown():void {
instance = null;
}
public function testInstantiated():void {
assertTrue("Example instantiated", instance is Example);
}
public function test():void {
assertTrue("failing test", false);
}
}
}
Thanks in advance for any help!
Robert
|
|
From: Luke B. <lb...@gm...> - 2007-02-17 02:04:11
|
Hey Brian, That's an interesting use case... I have to confess that it didn't occur to me to support async setup, and I'm sure that's not going to work without some hacking. I wonder if you could put the async handler in the test methods for now - and get the expected result until we can make some time to address this? Otherwise, if you find yourself fixing it in the TestCase class, please send us a patch! Thanks, Luke www.asunit.org |
|
From: John M. H. <ma...@ni...> - 2007-02-15 01:33:40
|
I've had this happen, seemingly at random. Occasionally it has looked like errors thrown while a constructor is running is the problem. Tom Cole wrote: > Hi everyone, > > I'm trying to get as25 working with my project in FlashDevelop > (compiling with MTASC). With one test class it works fine and I get > full output like this: > > AsUnit 2.5 by Luke Bayes and Ali Mills > ..F > > Time: 0.065 > There was 1 failure: > 0) com.saffroninter.lms.LMSAPITest.testMyCode() > assertTrue.message: This will fail! > > FAILURES!!! > Tests run: 2, Failures: 1, Errors: 0 > > However, if I add a second test class like this to my AllTests.as in > the package... > > addTest(new mypackage.MyClassOne()); > addTest(new mypackage.MyClassTwo ()); > > ..all I get is this in the output: > > AsUnit 2.5 by Luke Bayes and Ali Mills > ..F > > If you have seen this before or have any idea what I'm doing wrong, > please can you point me in the right direction. > > Many thanks, > > Tom > ------------------------------------------------------------------------ > > ------------------------------------------------------------------------- > Using Tomcat but need to do more? Need to support web services, security? > Get stuff done quickly with pre-integrated technology to make your job easier. > Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo > http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 > ------------------------------------------------------------------------ > > _______________________________________________ > Asunit-users mailing list > Asu...@li... > https://lists.sourceforge.net/lists/listinfo/asunit-users > |
|
From: Tom C. <tco...@go...> - 2007-02-13 13:02:06
|
Hi there, Following my previous mail I've done a bit of investigation. I've transferred a very simple example that works fine with the MXP Flash IDE version of ASUnit to my ASUnit 2.5 FlashDevelop/MTASC environment and when I add more than one TestCase to a TestSuite it falls over. Specifically, I think the setInterval in asunit.runner.BaseTestRunner is looping indefinitely: 47: intervalId = setInterval(this, "completionHandler", 1, suite, result, startTime); Following the code through, it looks as though in asunit.framework.TestSuitethere is a call to a global function (setTimeout) that I can't see defined anywhere else in the asunit package. 70: _global.setTimeout(this, "runTest", 10, itr, itr.next(), result); Looking at the change log, I'm guessing this part of the code may have been updated in r118. ------------------------------------------------------------------------ r118 | lukebayes | 2006-09-21 11:19:08 -0700 (Thu, 21 Sep 2006) | 1 line Changed paths: M /trunk/framework/as25/asunit/framework/TestSuite.as M /trunk/framework/as25/asunit/runner/BaseTestRunner.as A /trunk/framework/as25/asunit/util A /trunk/framework/as25/asunit/util/ArrayIterator.as A /trunk/framework/as25/asunit/util/ArrayIteratorTest.as A /trunk/framework/as25/asunit/util/Iterator.as added asynchronous execution of test suites to avoid script timeouts on large projects ------------------------------------------------------------------------ Maybe I'm doing something wrong, but I think now that there might be a bug here somewhere. I'm happy to send my file over if anyone wants to try it for themselves. Cheers, Tom On 12/02/07, Tom Cole <tco...@go...> wrote: > > Hi everyone, > > I'm trying to get as25 working with my project in FlashDevelop (compiling > with MTASC). With one test class it works fine and I get full output like > this: > > AsUnit 2.5 by Luke Bayes and Ali Mills > ..F > > Time: 0.065 > There was 1 failure: > 0) com.saffroninter.lms.LMSAPITest.testMyCode() > assertTrue.message: This will fail! > > FAILURES!!! > Tests run: 2, Failures: 1, Errors: 0 > > However, if I add a second test class like this to my AllTests.as in the > package... > > addTest(new mypackage.MyClassOne()); > addTest(new mypackage.MyClassTwo ()); > > ..all I get is this in the output: > > AsUnit 2.5 by Luke Bayes and Ali Mills > ..F > > If you have seen this before or have any idea what I'm doing wrong, please > can you point me in the right direction. > > Many thanks, > > Tom > |
|
From: Brian K. <bt...@gm...> - 2007-02-12 22:55:20
|
When I call addAsync in the setUp method of my tests I would expect it to work the same as if I was calling it in the context of a test method. But what I found is that it doesn't...instead of waiting for the async call to finish in the setUp method, asunit moves on to the test method - this causes a big issue because now the tests are running before the setup is complete. Please advise. Thanks, Brian -- Brian Knorr www.watij.com |
|
From: Tom C. <tco...@go...> - 2007-02-12 18:00:47
|
Hi everyone, I'm trying to get as25 working with my project in FlashDevelop (compiling with MTASC). With one test class it works fine and I get full output like this: AsUnit 2.5 by Luke Bayes and Ali Mills ..F Time: 0.065 There was 1 failure: 0) com.saffroninter.lms.LMSAPITest.testMyCode() assertTrue.message: This will fail! FAILURES!!! Tests run: 2, Failures: 1, Errors: 0 However, if I add a second test class like this to my AllTests.as in the package... addTest(new mypackage.MyClassOne()); addTest(new mypackage.MyClassTwo()); ..all I get is this in the output: AsUnit 2.5 by Luke Bayes and Ali Mills ..F If you have seen this before or have any idea what I'm doing wrong, please can you point me in the right direction. Many thanks, Tom |
|
From: Luke B. <lb...@gm...> - 2007-02-05 08:34:38
|
This definitely sounds interesting, but I'm completely jammed up these days and in need of some time away from the keyboard... Let us know if you get some traction on this. Thanks, Luke Bayes www.asunit.org I'm talking a la EasyMock/jMock/Dynamock etc. > > I know As2lib includes (amongst everything else) something based on > EasyMock (I think), but since I've made the investment in ASUnit for > testing, I'd rather use something lightweight and standalone that would > complement it. > > If there's nothing out there, is anyone interested in collaborating on > one? > > My primary requirement is still for AS2, but we could look to go the > parallel path for those who need AS3 support. > > |
|
From: Ian T. <Ia...@mo...> - 2007-02-02 11:54:19
|
Is anyone using / has anyone written a dynamic mock framework for AS2? =20 I'm talking a la EasyMock/jMock/Dynamock etc. I know As2lib includes (amongst everything else) something based on EasyMock (I think), but since I've made the investment in ASUnit for testing, I'd rather use something lightweight and standalone that would complement it. =20 If there's nothing out there, is anyone interested in collaborating on one? My primary requirement is still for AS2, but we could look to go the parallel path for those who need AS3 support. =20 Thanks. =20 Ian =20 Ian Tyrrell, Senior Developer, SiteMaker Software Ltd. =20 |
|
From: Robert P. <in...@ro...> - 2007-01-27 09:24:19
|
I updated to the latest SVN from tonight and ASUnit is compiling
now--thanks!
Robert
-----Original Message-----
From: Robert Penner [mailto:in...@ro...]
Sent: January 27, 2007 12:15 AM
To: Mailing List for the users of AsUnit
Subject: RE: [Asunit-users] asunit as3 doesn't compile with new Flex 2.01
Hi Luke,
I tried your new code below in Flex Builder Plugin 2.0.1 and it had the
same topLevelSystemManagers error. It also had an error on include
"../core/Version.as".
If you send code again, would it be possible to send a text file? The code
gets easily mangled by email (line breaks, tabs converted to spaces).
Thanks,
Robert
-----Original Message-----
From: asu...@li...
[mailto:asu...@li...]On Behalf Of Luke Bayes
Sent: January 26, 2007 7:22 PM
To: Mailing List for the users of AsUnit
Subject: Re: [Asunit-users] asunit as3 doesn't compile with new Flex 2.01
When I load in the as3 folder I get the following error:
1119: Access of possibly undefined property topLevelSystemManagers
through a reference with static type Class. Sandbox/mx/managers
LayoutManager.as line 319 1169846150182 3320
Hey Brian,
Thanks for the head up - there are actually a few things that I thought
were in the build that went out, but weren't... I'm not sure what went
wrong, but I'm hoping to get it sorted soon.
What you're encountering is actually a backwards compatibility issue
with the latest release of Flex Builder. The problem we were trying to solve
is this...
The Flex framework components register themselves with a global layout
manager when they are instantiated. This layout manager notifies them when
they need to update their display at some indeterminate point in the future
(It depends on what your component and it's children do).
AsUnit tries to build and destroy entities quickly, and sometimes calls
tearDown and removes those entities from the display list before the layout
manager has a chance to broadcast all of it's notifications. Since the
layout manager still has references to these objects, it's able to call
them - and then they often behave badly since they're no longer on the
display list.
My ugly hack to fix to this problem was to add a method to LayoutManager
named "resetAll". This method looks like this:
public function resetAll():void {
invalidatePropertiesQueue = new PriorityQueue();
invalidateSizeQueue = new PriorityQueue();
invalidateDisplayListQueue = new PriorityQueue();
invalidatePropertiesFlag = false;
invalidateClientSizeFlag = false;
invalidateDisplayListFlag = false;
}
I would have preferred to mix it in, or decorate it or *anything* other
than duplicate the class itself, but alas, AS3 limits our options...
Unfortunately, the new Flex Builder release includes some significant
refactoring to the framework and so the file that we released is now out of
date. To fix this issue, you can copy/paste the following into the file that
the compiler is complaining about and you should be good to go.
Thanks,
Luke Bayes
www.asunit.org
---------------------------8<----------------------------
////////////////////////////////////////////////////////////////////////
////////
//
// Copyright (C) 2003-2006 Adobe Macromedia Software LLC and its
licensors.
// All Rights Reserved. The following is Source Code and is subject to
all
// restrictions on such code as contained in the End User License
Agreement
// accompanying this product.
//
////////////////////////////////////////////////////////////////////////
////////
package mx.managers
{
import flash.display.Stage;
import flash.events.Event;
import flash.events.EventDispatcher;
import mx.core.Application;
import mx.core.UIComponent;
import mx.core.mx_internal;
import mx.events.FlexEvent;
import mx.managers.layoutClasses.PriorityQueue;
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
* (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 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>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>
*/
public class LayoutManager extends EventDispatcher
{
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.
*/
public static function getInstance():LayoutManager
{
if (!instance)
instance = new LayoutManager();
return instance;
}
//------------------------------------------------------------------
--------
//
// Constructor
//
//------------------------------------------------------------------
--------
/**
* Constructor.
*/
public function LayoutManager()
{
super();
}
//------------------------------------------------------------------
--------
//
// 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 callLaterObject:UIComponent;
/**
* @private
*/
private var callLaterPending: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;
//------------------------------------------------------------------
--------
//
// 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>
*/
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.
var stage:Stage =
SystemManager.topLevelSystemManagers[0].stage;
if (value)
{
originalFrameRate = stage.frameRate;
stage.frameRate = 1000;
}
else
{
stage.frameRate = originalFrameRate;
}
}
}
//------------------------------------------------------------------
--------
//
// 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.
*/
public function invalidateProperties(obj:ILayoutManagerClient ):void
{
if (!invalidatePropertiesFlag &&
Application.application.systemManager)
{
invalidatePropertiesFlag = true;
if (!callLaterPending)
{
if (!callLaterObject)
{
callLaterObject = new UIComponent();
callLaterObject.systemManager =
Application.application.systemManager;
callLaterObject.callLater(waitAFrame);
}
else
{
callLaterObject.callLater (doPhasedInstantiation);
}
callLaterPending = true;
}
}
// 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.
*/
public function invalidateSize(obj:ILayoutManagerClient ):void
{
if (!invalidateSizeFlag &&
Application.application.systemManager)
{
invalidateSizeFlag = true;
if (!callLaterPending)
{
if (!callLaterObject)
{
callLaterObject = new UIComponent();
callLaterObject.systemManager =
Application.application.systemManager;
callLaterObject.callLater(waitAFrame);
}
else
{
callLaterObject.callLater(doPhasedInstantiation);
}
callLaterPending = true;
}
}
// 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.
*/
public function
invalidateDisplayList(obj:ILayoutManagerClient ):void
{
if (!invalidateDisplayListFlag &&
Application.application.systemManager )
{
invalidateDisplayListFlag = true;
if (!callLaterPending)
{
if (!callLaterObject)
{
callLaterObject = new UIComponent();
callLaterObject.systemManager =
Application.application.systemManager;
callLaterObject.callLater(waitAFrame);
}
else
{
callLaterObject.callLater(doPhasedInstantiation);
}
callLaterPending = true;
}
}
// 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.
*/
private function validateProperties():void
{
// trace("--- LayoutManager: validateProperties --->");
// 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);
obj.validateProperties();
if (!obj.updateCompletePendingFlag)
{
updateCompleteQueue.addObject(obj, obj.nestLevel);
obj.updateCompletePendingFlag = true;
}
// Once we start, don't stop.
obj =
ILayoutManagerClient(invalidatePropertiesQueue.removeSmallest());
}
if (invalidatePropertiesQueue.isEmpty ())
{
// trace("Properties Queue is empty");
invalidatePropertiesFlag = false;
}
// trace("<--- LayoutManager: validateProperties ---");
}
/**
* 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
*/
private function validateSize():void
{
// trace("--- LayoutManager: validateSize --->");
var obj:ILayoutManagerClient = ILayoutManagerClient(
invalidateSizeQueue.removeLargest());
while (obj)
{
// trace("LayoutManager calling validateSize() on " +
Object(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);
obj =
ILayoutManagerClient(invalidateSizeQueue.removeLargest());
}
if (invalidateSizeQueue.isEmpty())
{
// trace("Measurement Queue is empty");
invalidateSizeFlag = false;
}
// 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
*
*/
private function validateDisplayList():void
{
// trace("--- LayoutManager: validateDisplayList --->");
var obj:ILayoutManagerClient = ILayoutManagerClient(
invalidateDisplayListQueue.removeSmallest());
while (obj)
{
// trace("LayoutManager calling validateDisplayList on " +
Object(obj) + " " + DisplayObject(obj).width + " " +
DisplayObject(obj).height);
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);
// Once we start, don't stop.
obj =
ILayoutManagerClient(invalidateDisplayListQueue.removeSmallest());
}
if (invalidateDisplayListQueue.isEmpty())
{
// trace("Layout Queue is empty");
invalidateDisplayListFlag = false;
}
// trace("<--- LayoutManager: validateDisplayList ---");
}
/**
* @private
*/
private function doPhasedInstantiation():void
{
// trace(">>DoPhasedInstantation");
// If phasing, do only one phase: validateProperties(),
// validateSize(), or validateDisplayList().
if (usePhasedInstantiation)
{
if (invalidatePropertiesFlag)
{
validateProperties();
// The Preloader listens for this event.
Application.application.dispatchEvent(
new Event("validatePropertiesComplete"));
}
else if (invalidateSizeFlag)
{
validateSize();
// The Preloader listens for this event.
Application.application.dispatchEvent(
new Event("validateSizeComplete"));
}
else if (invalidateDisplayListFlag)
{
validateDisplayList();
// The Preloader listens for this event.
Application.application.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)
{
callLaterObject.callLater(doPhasedInstantiation);
}
else
{
usePhasedInstantiation = false;
callLaterPending = false;
var obj:ILayoutManagerClient =
ILayoutManagerClient(updateCompleteQueue.removeLargest());
while (obj)
{
if (!obj.initialized && obj.processedDescriptors )
obj.initialized = true;
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.
*/
public function validateNow():void
{
if (!usePhasedInstantiation)
{
var infiniteLoopGuard:int = 0;
while (callLaterPending && 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.
*/
public function validateClient(target:ILayoutManagerClient ,
skipDisplayList:Boolean = false):void
{
var obj:ILayoutManagerClient;
var i:int = 0;
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);
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));
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);
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.initialized)
obj.initialized = true;
obj.dispatchEvent(new
FlexEvent(FlexEvent.UPDATE_COMPLETE ));
obj.updateCompletePendingFlag = false;
obj =
ILayoutManagerClient(updateCompleteQueue.removeLargestChild(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.
*/
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():void
{
//// trace(">>LayoutManager:WaitAFrame");
callLaterObject.callLater(doPhasedInstantiation);
//// trace("<<LayoutManager:WaitAFrame");
}
// METHOD ADDED BY ASUNIT
// This method prevents the LayoutManager from
// validating entities for whom tearDown has already been called...
public function resetAll():void {
invalidatePropertiesQueue = new PriorityQueue();
invalidateSizeQueue = new PriorityQueue();
invalidateDisplayListQueue = new PriorityQueue();
invalidatePropertiesFlag = false;
invalidateClientSizeFlag = false;
invalidateDisplayListFlag = false;
}
}
}
|
|
From: Robert P. <in...@ro...> - 2007-01-27 08:15:42
|
Hi Luke,
I tried your new code below in Flex Builder Plugin 2.0.1 and it had the same
topLevelSystemManagers error. It also had an error on include
"../core/Version.as".
If you send code again, would it be possible to send a text file? The code
gets easily mangled by email (line breaks, tabs converted to spaces).
Thanks,
Robert
-----Original Message-----
From: asu...@li...
[mailto:asu...@li...]On Behalf Of Luke Bayes
Sent: January 26, 2007 7:22 PM
To: Mailing List for the users of AsUnit
Subject: Re: [Asunit-users] asunit as3 doesn't compile with new Flex 2.01
When I load in the as3 folder I get the following error:
1119: Access of possibly undefined property topLevelSystemManagers
through a reference with static type Class. Sandbox/mx/managers
LayoutManager.as line 319 1169846150182 3320
Hey Brian,
Thanks for the head up - there are actually a few things that I thought
were in the build that went out, but weren't... I'm not sure what went
wrong, but I'm hoping to get it sorted soon.
What you're encountering is actually a backwards compatibility issue with
the latest release of Flex Builder. The problem we were trying to solve is
this...
The Flex framework components register themselves with a global layout
manager when they are instantiated. This layout manager notifies them when
they need to update their display at some indeterminate point in the future
(It depends on what your component and it's children do).
AsUnit tries to build and destroy entities quickly, and sometimes calls
tearDown and removes those entities from the display list before the layout
manager has a chance to broadcast all of it's notifications. Since the
layout manager still has references to these objects, it's able to call
them - and then they often behave badly since they're no longer on the
display list.
My ugly hack to fix to this problem was to add a method to LayoutManager
named "resetAll". This method looks like this:
public function resetAll():void {
invalidatePropertiesQueue = new PriorityQueue();
invalidateSizeQueue = new PriorityQueue();
invalidateDisplayListQueue = new PriorityQueue();
invalidatePropertiesFlag = false;
invalidateClientSizeFlag = false;
invalidateDisplayListFlag = false;
}
I would have preferred to mix it in, or decorate it or *anything* other
than duplicate the class itself, but alas, AS3 limits our options...
Unfortunately, the new Flex Builder release includes some significant
refactoring to the framework and so the file that we released is now out of
date. To fix this issue, you can copy/paste the following into the file that
the compiler is complaining about and you should be good to go.
Thanks,
Luke Bayes
www.asunit.org
---------------------------8<----------------------------
//////////////////////////////////////////////////////////////////////////
//////
//
// Copyright (C) 2003-2006 Adobe Macromedia Software LLC and its
licensors.
// All Rights Reserved. The following is Source Code and is subject to
all
// restrictions on such code as contained in the End User License
Agreement
// accompanying this product.
//
//////////////////////////////////////////////////////////////////////////
//////
package mx.managers
{
import flash.display.Stage;
import flash.events.Event;
import flash.events.EventDispatcher;
import mx.core.Application;
import mx.core.UIComponent;
import mx.core.mx_internal;
import mx.events.FlexEvent;
import mx.managers.layoutClasses.PriorityQueue;
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
* (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 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>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>
*/
public class LayoutManager extends EventDispatcher
{
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.
*/
public static function getInstance():LayoutManager
{
if (!instance)
instance = new LayoutManager();
return instance;
}
//--------------------------------------------------------------------
------
//
// Constructor
//
//--------------------------------------------------------------------
------
/**
* Constructor.
*/
public function LayoutManager()
{
super();
}
//--------------------------------------------------------------------
------
//
// 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 callLaterObject:UIComponent;
/**
* @private
*/
private var callLaterPending: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;
//--------------------------------------------------------------------
------
//
// 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>
*/
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.
var stage:Stage =
SystemManager.topLevelSystemManagers[0].stage;
if (value)
{
originalFrameRate = stage.frameRate;
stage.frameRate = 1000;
}
else
{
stage.frameRate = originalFrameRate;
}
}
}
//--------------------------------------------------------------------
------
//
// 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.
*/
public function invalidateProperties(obj:ILayoutManagerClient ):void
{
if (!invalidatePropertiesFlag &&
Application.application.systemManager)
{
invalidatePropertiesFlag = true;
if (!callLaterPending)
{
if (!callLaterObject)
{
callLaterObject = new UIComponent();
callLaterObject.systemManager =
Application.application.systemManager;
callLaterObject.callLater(waitAFrame);
}
else
{
callLaterObject.callLater (doPhasedInstantiation);
}
callLaterPending = true;
}
}
// 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.
*/
public function invalidateSize(obj:ILayoutManagerClient ):void
{
if (!invalidateSizeFlag && Application.application.systemManager)
{
invalidateSizeFlag = true;
if (!callLaterPending)
{
if (!callLaterObject)
{
callLaterObject = new UIComponent();
callLaterObject.systemManager =
Application.application.systemManager;
callLaterObject.callLater(waitAFrame);
}
else
{
callLaterObject.callLater(doPhasedInstantiation);
}
callLaterPending = true;
}
}
// 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.
*/
public function invalidateDisplayList(obj:ILayoutManagerClient ):void
{
if (!invalidateDisplayListFlag &&
Application.application.systemManager )
{
invalidateDisplayListFlag = true;
if (!callLaterPending)
{
if (!callLaterObject)
{
callLaterObject = new UIComponent();
callLaterObject.systemManager =
Application.application.systemManager;
callLaterObject.callLater(waitAFrame);
}
else
{
callLaterObject.callLater(doPhasedInstantiation);
}
callLaterPending = true;
}
}
// 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.
*/
private function validateProperties():void
{
// trace("--- LayoutManager: validateProperties --->");
// 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);
obj.validateProperties();
if (!obj.updateCompletePendingFlag)
{
updateCompleteQueue.addObject(obj, obj.nestLevel);
obj.updateCompletePendingFlag = true;
}
// Once we start, don't stop.
obj =
ILayoutManagerClient(invalidatePropertiesQueue.removeSmallest());
}
if (invalidatePropertiesQueue.isEmpty ())
{
// trace("Properties Queue is empty");
invalidatePropertiesFlag = false;
}
// trace("<--- LayoutManager: validateProperties ---");
}
/**
* 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
*/
private function validateSize():void
{
// trace("--- LayoutManager: validateSize --->");
var obj:ILayoutManagerClient = ILayoutManagerClient(
invalidateSizeQueue.removeLargest());
while (obj)
{
// trace("LayoutManager calling validateSize() on " +
Object(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);
obj =
ILayoutManagerClient(invalidateSizeQueue.removeLargest());
}
if (invalidateSizeQueue.isEmpty())
{
// trace("Measurement Queue is empty");
invalidateSizeFlag = false;
}
// 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
*
*/
private function validateDisplayList():void
{
// trace("--- LayoutManager: validateDisplayList --->");
var obj:ILayoutManagerClient = ILayoutManagerClient(
invalidateDisplayListQueue.removeSmallest());
while (obj)
{
// trace("LayoutManager calling validateDisplayList on " +
Object(obj) + " " + DisplayObject(obj).width + " " +
DisplayObject(obj).height);
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);
// Once we start, don't stop.
obj =
ILayoutManagerClient(invalidateDisplayListQueue.removeSmallest());
}
if (invalidateDisplayListQueue.isEmpty())
{
// trace("Layout Queue is empty");
invalidateDisplayListFlag = false;
}
// trace("<--- LayoutManager: validateDisplayList ---");
}
/**
* @private
*/
private function doPhasedInstantiation():void
{
// trace(">>DoPhasedInstantation");
// If phasing, do only one phase: validateProperties(),
// validateSize(), or validateDisplayList().
if (usePhasedInstantiation)
{
if (invalidatePropertiesFlag)
{
validateProperties();
// The Preloader listens for this event.
Application.application.dispatchEvent(
new Event("validatePropertiesComplete"));
}
else if (invalidateSizeFlag)
{
validateSize();
// The Preloader listens for this event.
Application.application.dispatchEvent(
new Event("validateSizeComplete"));
}
else if (invalidateDisplayListFlag)
{
validateDisplayList();
// The Preloader listens for this event.
Application.application.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)
{
callLaterObject.callLater(doPhasedInstantiation);
}
else
{
usePhasedInstantiation = false;
callLaterPending = false;
var obj:ILayoutManagerClient =
ILayoutManagerClient(updateCompleteQueue.removeLargest());
while (obj)
{
if (!obj.initialized && obj.processedDescriptors )
obj.initialized = true;
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.
*/
public function validateNow():void
{
if (!usePhasedInstantiation)
{
var infiniteLoopGuard:int = 0;
while (callLaterPending && 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.
*/
public function validateClient(target:ILayoutManagerClient ,
skipDisplayList:Boolean = false):void
{
var obj:ILayoutManagerClient;
var i:int = 0;
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);
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));
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);
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.initialized)
obj.initialized = true;
obj.dispatchEvent(new
FlexEvent(FlexEvent.UPDATE_COMPLETE ));
obj.updateCompletePendingFlag = false;
obj =
ILayoutManagerClient(updateCompleteQueue.removeLargestChild(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.
*/
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():void
{
//// trace(">>LayoutManager:WaitAFrame");
callLaterObject.callLater(doPhasedInstantiation);
//// trace("<<LayoutManager:WaitAFrame");
}
// METHOD ADDED BY ASUNIT
// This method prevents the LayoutManager from
// validating entities for whom tearDown has already been called...
public function resetAll():void {
invalidatePropertiesQueue = new PriorityQueue();
invalidateSizeQueue = new PriorityQueue();
invalidateDisplayListQueue = new PriorityQueue();
invalidatePropertiesFlag = false;
invalidateClientSizeFlag = false;
invalidateDisplayListFlag = false;
}
}
}
|
|
From: Luke B. <lb...@gm...> - 2007-01-27 03:35:59
|
OK - this one is working in my build, can someone please verify that this
works for them?
-------------------8<-------------------------------
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2003-2006 Adobe Macromedia Software LLC and its licensors.
// All Rights Reserved. The following is Source Code and is subject to all
// restrictions on such code as contained in the End User License Agreement
// accompanying this product.
//
////////////////////////////////////////////////////////////////////////////////
package mx.managers
{
import flash.display.Stage;
import flash.events.Event;
import flash.events.EventDispatcher;
import mx.core.Application;
import mx.core.UIComponent;
import mx.core.mx_internal;
import mx.events.FlexEvent;
import mx.managers.layoutClasses.PriorityQueue;
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
* (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 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>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>
*/
public class LayoutManager extends EventDispatcher
{
//--------------------------------------------------------------------------
//
// 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.
*/
public static function getInstance():LayoutManager
{
if (!instance)
instance = new LayoutManager();
return instance;
}
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*/
public function LayoutManager()
{
super();
}
//--------------------------------------------------------------------------
//
// 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 callLaterObject:UIComponent;
/**
* @private
*/
private var callLaterPending: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;
//--------------------------------------------------------------------------
//
// 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>
*/
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.
var stage:Stage = SystemManager.topLevelSystemManagers[0].stage;
if (value)
{
originalFrameRate = stage.frameRate;
stage.frameRate = 1000;
}
else
{
stage.frameRate = originalFrameRate;
}
}
}
//--------------------------------------------------------------------------
//
// 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.
*/
public function invalidateProperties(obj:ILayoutManagerClient ):void
{
if (!invalidatePropertiesFlag &&
Application.application.systemManager)
{
invalidatePropertiesFlag = true;
if (!callLaterPending)
{
if (!callLaterObject)
{
callLaterObject = new UIComponent();
callLaterObject.systemManager =
Application.application.systemManager;
callLaterObject.callLater(waitAFrame);
}
else
{
callLaterObject.callLater(doPhasedInstantiation);
}
callLaterPending = true;
}
}
// 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.
*/
public function invalidateSize(obj:ILayoutManagerClient ):void
{
if (!invalidateSizeFlag && Application.application.systemManager)
{
invalidateSizeFlag = true;
if (!callLaterPending)
{
if (!callLaterObject)
{
callLaterObject = new UIComponent();
callLaterObject.systemManager =
Application.application.systemManager;
callLaterObject.callLater(waitAFrame);
}
else
{
callLaterObject.callLater(doPhasedInstantiation);
}
callLaterPending = true;
}
}
// 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.
*/
public function invalidateDisplayList(obj:ILayoutManagerClient ):void
{
if (!invalidateDisplayListFlag &&
Application.application.systemManager)
{
invalidateDisplayListFlag = true;
if (!callLaterPending)
{
if (!callLaterObject)
{
callLaterObject = new UIComponent();
callLaterObject.systemManager =
Application.application.systemManager;
callLaterObject.callLater(waitAFrame);
}
else
{
callLaterObject.callLater(doPhasedInstantiation);
}
callLaterPending = true;
}
}
// 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.
*/
private function validateProperties():void
{
// trace("--- LayoutManager: validateProperties --->");
// 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);
obj.validateProperties();
if (!obj.updateCompletePendingFlag)
updateCompleteQueue.addObject(obj, obj.nestLevel);
// Once we start, don't stop.
obj = ILayoutManagerClient(
invalidatePropertiesQueue.removeSmallest());
}
if (invalidatePropertiesQueue.isEmpty())
{
// trace("Properties Queue is empty");
invalidatePropertiesFlag = false;
}
// trace("<--- LayoutManager: validateProperties ---");
}
/**
* 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
*/
private function validateSize():void
{
// trace("--- LayoutManager: validateSize --->");
var obj:ILayoutManagerClient = ILayoutManagerClient(
invalidateSizeQueue.removeLargest());
while (obj)
{
// trace("LayoutManager calling validateSize() on " +
Object(obj));
obj.validateSize();
if (!obj.updateCompletePendingFlag)
updateCompleteQueue.addObject(obj, obj.nestLevel);
// 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;
}
// 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
*
*/
private function validateDisplayList():void
{
// trace("--- LayoutManager: validateDisplayList --->");
var obj:ILayoutManagerClient = ILayoutManagerClient(
invalidateDisplayListQueue.removeSmallest());
while (obj)
{
// trace("LayoutManager calling validateDisplayList on " +
Object(obj) + " " + DisplayObject(obj).width + " " +
DisplayObject(obj).height);
obj.validateDisplayList();
if (!obj.updateCompletePendingFlag)
updateCompleteQueue.addObject(obj, obj.nestLevel);
// trace("LayoutManager return from validateDisplayList on " +
Object(obj) + " " + DisplayObject(obj).width + " " +
DisplayObject(obj).height);
// Once we start, don't stop.
obj = ILayoutManagerClient(
invalidateDisplayListQueue.removeSmallest());
}
if (invalidateDisplayListQueue.isEmpty())
{
// trace("Layout Queue is empty");
invalidateDisplayListFlag = false;
}
// trace("<--- LayoutManager: validateDisplayList ---");
}
/**
* @private
*/
private function doPhasedInstantiation():void
{
// trace(">>DoPhasedInstantation");
// If phasing, do only one phase: validateProperties(),
// validateSize(), or validateDisplayList().
if (usePhasedInstantiation)
{
if (invalidatePropertiesFlag)
{
validateProperties();
// The Preloader listens for this event.
Application.application.dispatchEvent(
new Event("validatePropertiesComplete"));
}
else if (invalidateSizeFlag)
{
validateSize();
// The Preloader listens for this event.
Application.application.dispatchEvent(
new Event("validateSizeComplete"));
}
else if (invalidateDisplayListFlag)
{
validateDisplayList();
// The Preloader listens for this event.
Application.application.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)
{
callLaterObject.callLater(doPhasedInstantiation);
}
else
{
usePhasedInstantiation = false;
callLaterPending = false;
var obj:ILayoutManagerClient = ILayoutManagerClient(
updateCompleteQueue.removeLargest());
while (obj)
{
if (!obj.initialized && obj.processedDescriptors)
obj.initialized = true;
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.
*/
public function validateNow():void
{
if (!usePhasedInstantiation)
{
var infiniteLoopGuard:int = 0;
while (callLaterPending && 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.
*/
public function validateClient(target:ILayoutManagerClient ,
skipDisplayList:Boolean = false):void
{
var obj:ILayoutManagerClient;
var i:int = 0;
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);
obj.validateProperties();
if (!obj.updateCompletePendingFlag)
updateCompleteQueue.addObject(obj, obj.nestLevel);
// 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));
obj.validateSize();
if (!obj.updateCompletePendingFlag)
updateCompleteQueue.addObject(obj, obj.nestLevel);
// 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);
obj.validateDisplayList();
if (!obj.updateCompletePendingFlag)
updateCompleteQueue.addObject(obj, obj.nestLevel);
// 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.initialized)
obj.initialized = true;
obj.dispatchEvent(new FlexEvent(
FlexEvent.UPDATE_COMPLETE));
obj.updateCompletePendingFlag = false;
obj = ILayoutManagerClient(
updateCompleteQueue.removeLargestChild(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.
*/
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():void
{
//// trace(">>LayoutManager:WaitAFrame");
callLaterObject.callLater(doPhasedInstantiation);
//// trace("<<LayoutManager:WaitAFrame");
}
// METHOD ADDED BY ASUNIT
// This method prevents the LayoutManager from
// validating entities for whom tearDown has already been called...
public function resetAll():void {
invalidatePropertiesQueue = new PriorityQueue();
invalidateSizeQueue = new PriorityQueue();
invalidateDisplayListQueue = new PriorityQueue();
invalidatePropertiesFlag = false;
invalidateClientSizeFlag = false;
invalidateDisplayListFlag = false;
}
}
}
|
|
From: Luke B. <lb...@gm...> - 2007-01-27 03:26:26
|
Just a minute - That file won't work either. I'll get another one out in a minute... lb. |
|
From: Luke B. <lb...@gm...> - 2007-01-27 03:22:03
|
>
> When I load in the as3 folder I get the following error:
>
> 1119: Access of possibly undefined property topLevelSystemManagers through
> a reference with static type Class. Sandbox/mx/managers
> LayoutManager.as line 319 1169846150182 3320
>
Hey Brian,
Thanks for the head up - there are actually a few things that I thought were
in the build that went out, but weren't... I'm not sure what went wrong, but
I'm hoping to get it sorted soon.
What you're encountering is actually a backwards compatibility issue with
the latest release of Flex Builder. The problem we were trying to solve is
this...
The Flex framework components register themselves with a global layout
manager when they are instantiated. This layout manager notifies them when
they need to update their display at some indeterminate point in the future
(It depends on what your component and it's children do).
AsUnit tries to build and destroy entities quickly, and sometimes calls
tearDown and removes those entities from the display list before the layout
manager has a chance to broadcast all of it's notifications. Since the
layout manager still has references to these objects, it's able to call them
- and then they often behave badly since they're no longer on the display
list.
My ugly hack to fix to this problem was to add a method to LayoutManager
named "resetAll". This method looks like this:
public function resetAll():void {
invalidatePropertiesQueue = new PriorityQueue();
invalidateSizeQueue = new PriorityQueue();
invalidateDisplayListQueue = new PriorityQueue();
invalidatePropertiesFlag = false;
invalidateClientSizeFlag = false;
invalidateDisplayListFlag = false;
}
I would have preferred to mix it in, or decorate it or *anything* other than
duplicate the class itself, but alas, AS3 limits our options...
Unfortunately, the new Flex Builder release includes some significant
refactoring to the framework and so the file that we released is now out of
date. To fix this issue, you can copy/paste the following into the file that
the compiler is complaining about and you should be good to go.
Thanks,
Luke Bayes
www.asunit.org
---------------------------8<----------------------------
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2003-2006 Adobe Macromedia Software LLC and its licensors.
// All Rights Reserved. The following is Source Code and is subject to all
// restrictions on such code as contained in the End User License Agreement
// accompanying this product.
//
////////////////////////////////////////////////////////////////////////////////
package mx.managers
{
import flash.display.Stage;
import flash.events.Event;
import flash.events.EventDispatcher;
import mx.core.Application;
import mx.core.UIComponent;
import mx.core.mx_internal;
import mx.events.FlexEvent;
import mx.managers.layoutClasses.PriorityQueue;
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
* (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 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>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>
*/
public class LayoutManager extends EventDispatcher
{
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.
*/
public static function getInstance():LayoutManager
{
if (!instance)
instance = new LayoutManager();
return instance;
}
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*/
public function LayoutManager()
{
super();
}
//--------------------------------------------------------------------------
//
// 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 callLaterObject:UIComponent;
/**
* @private
*/
private var callLaterPending: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;
//--------------------------------------------------------------------------
//
// 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>
*/
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.
var stage:Stage = SystemManager.topLevelSystemManagers[0].stage;
if (value)
{
originalFrameRate = stage.frameRate;
stage.frameRate = 1000;
}
else
{
stage.frameRate = originalFrameRate;
}
}
}
//--------------------------------------------------------------------------
//
// 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.
*/
public function invalidateProperties(obj:ILayoutManagerClient ):void
{
if (!invalidatePropertiesFlag &&
Application.application.systemManager)
{
invalidatePropertiesFlag = true;
if (!callLaterPending)
{
if (!callLaterObject)
{
callLaterObject = new UIComponent();
callLaterObject.systemManager =
Application.application.systemManager;
callLaterObject.callLater(waitAFrame);
}
else
{
callLaterObject.callLater(doPhasedInstantiation);
}
callLaterPending = true;
}
}
// 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.
*/
public function invalidateSize(obj:ILayoutManagerClient ):void
{
if (!invalidateSizeFlag && Application.application.systemManager)
{
invalidateSizeFlag = true;
if (!callLaterPending)
{
if (!callLaterObject)
{
callLaterObject = new UIComponent();
callLaterObject.systemManager =
Application.application.systemManager;
callLaterObject.callLater(waitAFrame);
}
else
{
callLaterObject.callLater(doPhasedInstantiation);
}
callLaterPending = true;
}
}
// 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.
*/
public function invalidateDisplayList(obj:ILayoutManagerClient ):void
{
if (!invalidateDisplayListFlag &&
Application.application.systemManager)
{
invalidateDisplayListFlag = true;
if (!callLaterPending)
{
if (!callLaterObject)
{
callLaterObject = new UIComponent();
callLaterObject.systemManager =
Application.application.systemManager;
callLaterObject.callLater(waitAFrame);
}
else
{
callLaterObject.callLater(doPhasedInstantiation);
}
callLaterPending = true;
}
}
// 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.
*/
private function validateProperties():void
{
// trace("--- LayoutManager: validateProperties --->");
// 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);
obj.validateProperties();
if (!obj.updateCompletePendingFlag)
{
updateCompleteQueue.addObject(obj, obj.nestLevel);
obj.updateCompletePendingFlag = true;
}
// Once we start, don't stop.
obj = ILayoutManagerClient(
invalidatePropertiesQueue.removeSmallest());
}
if (invalidatePropertiesQueue.isEmpty())
{
// trace("Properties Queue is empty");
invalidatePropertiesFlag = false;
}
// trace("<--- LayoutManager: validateProperties ---");
}
/**
* 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
*/
private function validateSize():void
{
// trace("--- LayoutManager: validateSize --->");
var obj:ILayoutManagerClient = ILayoutManagerClient(
invalidateSizeQueue.removeLargest());
while (obj)
{
// trace("LayoutManager calling validateSize() on " +
Object(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);
obj = ILayoutManagerClient(invalidateSizeQueue.removeLargest());
}
if (invalidateSizeQueue.isEmpty())
{
// trace("Measurement Queue is empty");
invalidateSizeFlag = false;
}
// 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
*
*/
private function validateDisplayList():void
{
// trace("--- LayoutManager: validateDisplayList --->");
var obj:ILayoutManagerClient = ILayoutManagerClient(
invalidateDisplayListQueue.removeSmallest());
while (obj)
{
// trace("LayoutManager calling validateDisplayList on " +
Object(obj) + " " + DisplayObject(obj).width + " " +
DisplayObject(obj).height);
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);
// Once we start, don't stop.
obj = ILayoutManagerClient(
invalidateDisplayListQueue.removeSmallest());
}
if (invalidateDisplayListQueue.isEmpty())
{
// trace("Layout Queue is empty");
invalidateDisplayListFlag = false;
}
// trace("<--- LayoutManager: validateDisplayList ---");
}
/**
* @private
*/
private function doPhasedInstantiation():void
{
// trace(">>DoPhasedInstantation");
// If phasing, do only one phase: validateProperties(),
// validateSize(), or validateDisplayList().
if (usePhasedInstantiation)
{
if (invalidatePropertiesFlag)
{
validateProperties();
// The Preloader listens for this event.
Application.application.dispatchEvent(
new Event("validatePropertiesComplete"));
}
else if (invalidateSizeFlag)
{
validateSize();
// The Preloader listens for this event.
Application.application.dispatchEvent(
new Event("validateSizeComplete"));
}
else if (invalidateDisplayListFlag)
{
validateDisplayList();
// The Preloader listens for this event.
Application.application.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)
{
callLaterObject.callLater(doPhasedInstantiation);
}
else
{
usePhasedInstantiation = false;
callLaterPending = false;
var obj:ILayoutManagerClient = ILayoutManagerClient(
updateCompleteQueue.removeLargest());
while (obj)
{
if (!obj.initialized && obj.processedDescriptors)
obj.initialized = true;
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.
*/
public function validateNow():void
{
if (!usePhasedInstantiation)
{
var infiniteLoopGuard:int = 0;
while (callLaterPending && 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.
*/
public function validateClient(target:ILayoutManagerClient ,
skipDisplayList:Boolean = false):void
{
var obj:ILayoutManagerClient;
var i:int = 0;
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);
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));
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);
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.initialized)
obj.initialized = true;
obj.dispatchEvent(new FlexEvent(
FlexEvent.UPDATE_COMPLETE));
obj.updateCompletePendingFlag = false;
obj = ILayoutManagerClient(
updateCompleteQueue.removeLargestChild(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.
*/
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():void
{
//// trace(">>LayoutManager:WaitAFrame");
callLaterObject.callLater(doPhasedInstantiation);
//// trace("<<LayoutManager:WaitAFrame");
}
// METHOD ADDED BY ASUNIT
// This method prevents the LayoutManager from
// validating entities for whom tearDown has already been called...
public function resetAll():void {
invalidatePropertiesQueue = new PriorityQueue();
invalidateSizeQueue = new PriorityQueue();
invalidateDisplayListQueue = new PriorityQueue();
invalidatePropertiesFlag = false;
invalidateClientSizeFlag = false;
invalidateDisplayListFlag = false;
}
}
}
|
|
From: Brian K. <bt...@gm...> - 2007-01-26 21:16:29
|
When I load in the as3 folder I get the following error: 1119: Access of possibly undefined property topLevelSystemManagers through a reference with static type Class. Sandbox/mx/managers LayoutManager.as line 319 1169846150182 3320 -- Brian Knorr www.watij.com |
|
From: Luke B. <lb...@gm...> - 2007-01-12 20:54:35
|
Hey Kevin, We both really appreciate your post as it forced us to get this build out the door! Please feel free to ask any other questions that come up. Thanks, Luke Bayes www.asunit.org |
|
From: Kevin F. <ke...@ke...> - 2007-01-10 21:19:38
|
Thanks Luke, Everything in the new build 20070109 seems great! -Kevin Fitzpatrick On 1/8/07 8:58 PM, "Luke Bayes" <lb...@gm...> wrote: > Thanks Kevin, > > Ok - We just put a new Framework and XULUI.msi build up on sourceforge. The OS > X installer has not been rebuilt, I'll check in with Aral about getting that > done soon. > > Sorry our releases have been so far apart and sorry the posted builds haven't > been working properly! > > OK - At this point, the mxp is still out of date, but the Framework.zip and > XULUI.msi are both current. > > I have to get home so the mxp will have to wait for another day! > > > Thanks, > > > Luke Bayes > www.asunit.org <http://www.asunit.org> > > > > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share your > opinions on IT & business topics through brief surveys - and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > > _______________________________________________ > Asunit-users mailing list > Asu...@li... > https://lists.sourceforge.net/lists/listinfo/asunit-users |
|
From: Luke B. <lb...@gm...> - 2007-01-09 01:58:31
|
Thanks Kevin, Ok - We just put a new Framework and XULUI.msi build up on sourceforge. The OS X installer has not been rebuilt, I'll check in with Aral about getting that done soon. Sorry our releases have been so far apart and sorry the posted builds haven't been working properly! OK - At this point, the mxp is still out of date, but the Framework.zip and XULUI.msi are both current. I have to get home so the mxp will have to wait for another day! Thanks, Luke Bayes www.asunit.org |
|
From: Kevin F. <ke...@ke...> - 2007-01-09 01:38:31
|
Luke, I believe (and I stress =B3believe=B2) I downloaded the framework zip and then redownloaded it at one point to make sure. I was messing around with the 3.0.1 alpha at one point, but when I definitely went back again to get the full framework. I=B9ll check out the new build and see what=B9s up. BTW, I don=B9t know if the site cares at all (doesn=B9t look like it) but I=B9m running OS X 10.4 on a MacBook Pro. Thanks, Kevin=20 1/8/07 7:06 PM, "Luke Bayes" <lb...@gm...> wrote: > Hey Kevin, >=20 > It sounds like you have some sources from way back in beta 2, I'm really > curious which build you downloaded - I just found some different compile > errors in the latest release of the Framework.zip package... >=20 > Did you get the XUL UI? the Framework.zip? or the MXP installer? >=20 > We're way overdue on a release at this point... >=20 > I'm going to drop a new build for the Framework.zip right now - but it's = going > to take some time to get the other two releases synced up. >=20 > Thanks for the post! >=20 >=20 > Luke Bayes > www.asunit.org <http://www.asunit.org> >=20 >=20 >=20 >=20 > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share y= our > opinions on IT & business topics through brief surveys - and earn cash > http://www.techsay.com/default.php?page=3Djoin.php&p=3Dsourceforge&CID=3DDEVDEV >=20 > _______________________________________________ > Asunit-users mailing list > Asu...@li... > https://lists.sourceforge.net/lists/listinfo/asunit-users |
|
From: Luke B. <lb...@gm...> - 2007-01-09 00:06:15
|
Hey Kevin, It sounds like you have some sources from way back in beta 2, I'm really curious which build you downloaded - I just found some different compile errors in the latest release of the Framework.zip package... Did you get the XUL UI? the Framework.zip? or the MXP installer? We're way overdue on a release at this point... I'm going to drop a new build for the Framework.zip right now - but it's going to take some time to get the other two releases synced up. Thanks for the post! Luke Bayes www.asunit.org |
|
From: Kevin F. <ke...@ke...> - 2007-01-08 21:59:24
|
Hey all, just getting started with AsUnit here and I'm hitting a wall here pretty early on. I'm working in Flex Builder 2 in AS 3 projects. I'm looking at the framework and I'm getting compilation errors all over the place. I'm wondering if I have a bad copy or something. I'm seeing things like "flash.util.trace" and "flash.util.describeType" instead of "flash.utils.describeType" I'm fully willing to believe that I don't have a clue what I'm doing here. I'm a bit confused; any thoughts would be helpful. Thanks, Kevin |
|
From: Marcelo de M. S. <cel...@gm...> - 2006-12-30 00:31:56
|
Hi Luke, Does that help? > A lot! Thank you very much for taking your time to help me. Marcelo. On 12/29/06, Luke Bayes <lb...@gm...> wrote: > > Hey Marcelo, > > We definitely don't ship test code in our production swf files, but we do > make sure that everything our production code has access to, is available in > our test harness. Regardless of how you physically segment test classes from > production code, the compiler will only include classes that are referenced > one way or another from the main class (MTASC), the main timeline, or > exported symbols (FLA). test cases point at production code, but production > code never references test cases. We have seen projects built with the test > classes alongside the production classes, test packages inside production > packages and like you, have settled on the mirrored test package approach. > Basically, it doesn't matter where the test classes are as long as nothing > from your production compilation references them. > > In environments where we have to use a fla file, we use authoring to > compile it once, then tell MTASC to use the resulting swf file as 'input'. > When you do this, mtasc has access to all those visual assets by their > linkage ids - forms and animations and whatnot. I also (quite handily) > clobbers all ActionScript classes and replaces them with bytecode from it's > compilation. This is a rather simple compiler flag available in MTASC. > > This process tends to work pretty well since we generally modify the code > much more frequently than the visual asset fla. I wouldn't recommend > creating multiple, separate fla files for each different form as this can > make sharing assets and clean compilation much more complicated. > > When you say, "I don't insert any code on the fla file at all. Everything > is coded on external AS2 classes", of course we don't write any ActionScript > in the authoring tool, but we do associate ActionScript 2 classes with > symbols in the fla library using the symbol properties dialog. This > generally seems to work fine - even when post-compiling using MTASC. But the > point is that we wind up with a fla/swf file that is compiled with MMC > (Authoring) - then use MTASC to build the deployed and test harness SWF > files. If we were going to try building something modular that could load > separate content swfs as needed, I suspect we would use a similar process, > using MTASC exclude directives to make the subsequent modular swfs... > > As far as MovieClip instantiation that relies on symbols that aren't > available in the test harness, I would argue that a test swf that doesn't > include everything that exists in the production swf is not thoroughly > testing your production functionality. > > Does that help? > > > Thanks, > > > Luke Bayes > www.asunit.org > > > > On 12/29/06, Marcelo de Moraes Serpa wrote: > > > > This line is usually switched from running our application main function > > > to running our test suite main function > > > > > > I couldn't really understand, Luke. The way I'm doing right now is > > having a test swf and that is all. The way you put it, seems like you mix > > test code with production code, is that right? > > > > Let me explain better how I've set up my unit testing workflow: > > > > I'm using AS2ANT unittest task. So, I compile the TestRunner into a swf > > file and run it before proceeding with the rest of the build. I have two > > identical project trees - one for the production source files and one for > > theses classes' test classes, like this: > > > > * com.cconline.views.IndexView > > * tests.com.cconline.views.IndexViewTest > > > > All the main test classes (TestSuite and TestRunner) are on the test.* > > namespace. > > > > My project consists of various .fla files, one for each of the > > application's views (forms). I find fla's easier for making complex > > design-oriented layouts and sometimes animations. I don't insert any code on > > the fla file at all. Everything is coded on external AS2 classes. > > > > It wasn't also clear on how should I handle MovieClip instantiation on > > the test swf when this MovieClip relies on assets that are not present on > > the test swf's library. > > > > Thanks a lot for the help! > > > > Marcelo. > > > > On 12/29/06, Luke Bayes < lb...@gm...> wrote: > > > > > > Hey Marcelo, > > > > > > There are a couple of issues you're talking about here, I'm going to > > > restate them a little differently, please let me know if this is inaccurate. > > > > > > 1) Should I ever write a unit test for a visual entity? > > > Yes. There are definitely times when views have code. Even using MVC, > > > the view is responsible for some work and unit testing can verify that this > > > work is being done as expected. > > > > > > 2) How do I structure an application for unit testing? > > > Ali and I spent a considerable amount of time thinking about this > > > problem, and after quite a bit of trial and error, we realized that one of > > > the most important aspects to testing is that the environment your test > > > harness operates in should be as nearly identical to your production > > > environment as possible. This includes library assets, frameworks, etc... > > > For example, Macromedia's components manipulate some core object prototypes, > > > add functions to _global and place assets on _root in a very high level > > > which affects our ability to use _root.getNextHighestDepth(). IF we are > > > using components in our application, but fail to load that library into our > > > test swf, we will see behaviors in production that are very different from > > > those that we find in our tests. > > > > > > We generally try to avoid using a fla file if at all possible, but if > > > we are forced to use a .fla file for a project, the most important thing > > > that we do, is avoid doing any real work on the main timeline. If we have > > > some animation or some frame-based work that needs done, we put it into a > > > MovieClip. The main timeline of our .fla files generally has one line of > > > ActionScript. This line is usually switched from running our application > > > main function to running our test suite main function. This has the added > > > benefit of allowing us to point MTASC at either of these main functions and > > > simply swallow the MMC-compiled swf file. > > > > > > // SomeApplication.main(); > > > SomeApplicationRunner.main(); > > > > > > I hope that helps. > > > > > > > > > Luke Bayes > > > www.asunit.org > > > > > > > > > On 12/29/06, Marcelo de Moraes Serpa wrote: > > > > > > > > Hi Luke, thanks for the reply :) > > > > > > > > It is still not clear to me the role of MovieClip classes on asunit > > > > unit tests. From what I've been reading about Unit Testing so far, I can > > > > understand that visual entities should not be unit tested directly. Instead, > > > > the business classes that are used by it should be tested and I don't think > > > > business classes should inherit MovieClip (am I misunderstanding something > > > > here?). > > > > > > > > But let's say I really want to instantiate a MovieClip class on my > > > > unit test. The XUL UI feature you described is for creating mock objects for > > > > MovieClip classes, right? I'm asking this becouse it would be too much of a > > > > stress to try to instantiate a regular "non-serializable" MovieClip class as > > > > it depends on assets that are not present on the test swf library (and > > > > should not be present, I'm almost sure!). > > > > > > > > Cheers, > > > > > > > > Marcelo. > > > > > > > > > > > > > > > > > ------------------------------------------------------------------------- > > > Take Surveys. Earn Cash. Influence the Future of IT > > > Join SourceForge.net's Techsay panel and you'll get the chance to > > > share your > > > opinions on IT & business topics through brief surveys - and earn cash > > > > > > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > > > > > > _______________________________________________ > > > Asunit-users mailing list > > > Asu...@li... > > > https://lists.sourceforge.net/lists/listinfo/asunit-users > > > > > > > > > > > > > > > ------------------------------------------------------------------------- > > Take Surveys. Earn Cash. Influence the Future of IT > > Join SourceForge.net's Techsay panel and you'll get the chance to share > > your > > opinions on IT & business topics through brief surveys - and earn cash > > > > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > > > > _______________________________________________ > > Asunit-users mailing list > > Asu...@li... > > https://lists.sourceforge.net/lists/listinfo/asunit-users > > > > > > > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share > your > opinions on IT & business topics through brief surveys - and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > > _______________________________________________ > Asunit-users mailing list > Asu...@li... > https://lists.sourceforge.net/lists/listinfo/asunit-users > > > |
|
From: Luke B. <lb...@gm...> - 2006-12-29 23:12:24
|
Hey Marcelo, We definitely don't ship test code in our production swf files, but we do make sure that everything our production code has access to, is available in our test harness. Regardless of how you physically segment test classes from production code, the compiler will only include classes that are referenced one way or another from the main class (MTASC), the main timeline, or exported symbols (FLA). test cases point at production code, but production code never references test cases. We have seen projects built with the test classes alongside the production classes, test packages inside production packages and like you, have settled on the mirrored test package approach. Basically, it doesn't matter where the test classes are as long as nothing from your production compilation references them. In environments where we have to use a fla file, we use authoring to compile it once, then tell MTASC to use the resulting swf file as 'input'. When you do this, mtasc has access to all those visual assets by their linkage ids - forms and animations and whatnot. I also (quite handily) clobbers all ActionScript classes and replaces them with bytecode from it's compilation. This is a rather simple compiler flag available in MTASC. This process tends to work pretty well since we generally modify the code much more frequently than the visual asset fla. I wouldn't recommend creating multiple, separate fla files for each different form as this can make sharing assets and clean compilation much more complicated. When you say, "I don't insert any code on the fla file at all. Everything is coded on external AS2 classes", of course we don't write any ActionScript in the authoring tool, but we do associate ActionScript 2 classes with symbols in the fla library using the symbol properties dialog. This generally seems to work fine - even when post-compiling using MTASC. But the point is that we wind up with a fla/swf file that is compiled with MMC (Authoring) - then use MTASC to build the deployed and test harness SWF files. If we were going to try building something modular that could load separate content swfs as needed, I suspect we would use a similar process, using MTASC exclude directives to make the subsequent modular swfs... As far as MovieClip instantiation that relies on symbols that aren't available in the test harness, I would argue that a test swf that doesn't include everything that exists in the production swf is not thoroughly testing your production functionality. Does that help? Thanks, Luke Bayes www.asunit.org On 12/29/06, Marcelo de Moraes Serpa wrote: > > This line is usually switched from running our application main function > > to running our test suite main function > > > I couldn't really understand, Luke. The way I'm doing right now is having > a test swf and that is all. The way you put it, seems like you mix test code > with production code, is that right? > > Let me explain better how I've set up my unit testing workflow: > > I'm using AS2ANT unittest task. So, I compile the TestRunner into a swf > file and run it before proceeding with the rest of the build. I have two > identical project trees - one for the production source files and one for > theses classes' test classes, like this: > > * com.cconline.views.IndexView > * tests.com.cconline.views.IndexViewTest > > All the main test classes (TestSuite and TestRunner) are on the test.* > namespace. > > My project consists of various .fla files, one for each of the > application's views (forms). I find fla's easier for making complex > design-oriented layouts and sometimes animations. I don't insert any code on > the fla file at all. Everything is coded on external AS2 classes. > > It wasn't also clear on how should I handle MovieClip instantiation on the > test swf when this MovieClip relies on assets that are not present on the > test swf's library. > > Thanks a lot for the help! > > Marcelo. > > On 12/29/06, Luke Bayes <lb...@gm...> wrote: > > > > Hey Marcelo, > > > > There are a couple of issues you're talking about here, I'm going to > > restate them a little differently, please let me know if this is inaccurate. > > > > 1) Should I ever write a unit test for a visual entity? > > Yes. There are definitely times when views have code. Even using MVC, > > the view is responsible for some work and unit testing can verify that this > > work is being done as expected. > > > > 2) How do I structure an application for unit testing? > > Ali and I spent a considerable amount of time thinking about this > > problem, and after quite a bit of trial and error, we realized that one of > > the most important aspects to testing is that the environment your test > > harness operates in should be as nearly identical to your production > > environment as possible. This includes library assets, frameworks, etc... > > For example, Macromedia's components manipulate some core object prototypes, > > add functions to _global and place assets on _root in a very high level > > which affects our ability to use _root.getNextHighestDepth(). IF we are > > using components in our application, but fail to load that library into our > > test swf, we will see behaviors in production that are very different from > > those that we find in our tests. > > > > We generally try to avoid using a fla file if at all possible, but if we > > are forced to use a .fla file for a project, the most important thing that > > we do, is avoid doing any real work on the main timeline. If we have some > > animation or some frame-based work that needs done, we put it into a > > MovieClip. The main timeline of our .fla files generally has one line of > > ActionScript. This line is usually switched from running our application > > main function to running our test suite main function. This has the added > > benefit of allowing us to point MTASC at either of these main functions and > > simply swallow the MMC-compiled swf file. > > > > // SomeApplication.main(); > > SomeApplicationRunner.main(); > > > > I hope that helps. > > > > > > Luke Bayes > > www.asunit.org > > > > > > On 12/29/06, Marcelo de Moraes Serpa wrote: > > > > > > Hi Luke, thanks for the reply :) > > > > > > It is still not clear to me the role of MovieClip classes on asunit > > > unit tests. From what I've been reading about Unit Testing so far, I can > > > understand that visual entities should not be unit tested directly. Instead, > > > the business classes that are used by it should be tested and I don't think > > > business classes should inherit MovieClip (am I misunderstanding something > > > here?). > > > > > > But let's say I really want to instantiate a MovieClip class on my > > > unit test. The XUL UI feature you described is for creating mock objects for > > > MovieClip classes, right? I'm asking this becouse it would be too much of a > > > stress to try to instantiate a regular "non-serializable" MovieClip class as > > > it depends on assets that are not present on the test swf library (and > > > should not be present, I'm almost sure!). > > > > > > Cheers, > > > > > > Marcelo. > > > > > > > > > > > > ------------------------------------------------------------------------- > > Take Surveys. Earn Cash. Influence the Future of IT > > Join SourceForge.net's Techsay panel and you'll get the chance to share > > your > > opinions on IT & business topics through brief surveys - and earn cash > > > > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > > > > _______________________________________________ > > Asunit-users mailing list > > Asu...@li... > > https://lists.sourceforge.net/lists/listinfo/asunit-users > > > > > > > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share > your > opinions on IT & business topics through brief surveys - and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > > _______________________________________________ > Asunit-users mailing list > Asu...@li... > https://lists.sourceforge.net/lists/listinfo/asunit-users > > > |
|
From: Marcelo de M. S. <cel...@gm...> - 2006-12-29 19:39:38
|
> > This line is usually switched from running our application main function > to running our test suite main function I couldn't really understand, Luke. The way I'm doing right now is having a test swf and that is all. The way you put it, seems like you mix test code with production code, is that right? Let me explain better how I've set up my unit testing workflow: I'm using AS2ANT unittest task. So, I compile the TestRunner into a swf file and run it before proceeding with the rest of the build. I have two identical project trees - one for the production source files and one for theses classes' test classes, like this: * com.cconline.views.IndexView * tests.com.cconline.views.IndexViewTest All the main test classes (TestSuite and TestRunner) are on the test.* namespace. My project consists of various .fla files, one for each of the application's views (forms). I find fla's easier for making complex design-oriented layouts and sometimes animations. I don't insert any code on the fla file at all. Everything is coded on external AS2 classes. It wasn't also clear on how should I handle MovieClip instantiation on the test swf when this MovieClip relies on assets that are not present on the test swf's library. Thanks a lot for the help! Marcelo. On 12/29/06, Luke Bayes <lb...@gm...> wrote: > > Hey Marcelo, > > There are a couple of issues you're talking about here, I'm going to > restate them a little differently, please let me know if this is inaccurate. > > 1) Should I ever write a unit test for a visual entity? > Yes. There are definitely times when views have code. Even using MVC, the > view is responsible for some work and unit testing can verify that this work > is being done as expected. > > 2) How do I structure an application for unit testing? > Ali and I spent a considerable amount of time thinking about this problem, > and after quite a bit of trial and error, we realized that one of the most > important aspects to testing is that the environment your test harness > operates in should be as nearly identical to your production environment as > possible. This includes library assets, frameworks, etc... For example, > Macromedia's components manipulate some core object prototypes, add > functions to _global and place assets on _root in a very high level which > affects our ability to use _root.getNextHighestDepth(). IF we are using > components in our application, but fail to load that library into our test > swf, we will see behaviors in production that are very different from those > that we find in our tests. > > We generally try to avoid using a fla file if at all possible, but if we > are forced to use a .fla file for a project, the most important thing that > we do, is avoid doing any real work on the main timeline. If we have some > animation or some frame-based work that needs done, we put it into a > MovieClip. The main timeline of our .fla files generally has one line of > ActionScript. This line is usually switched from running our application > main function to running our test suite main function. This has the added > benefit of allowing us to point MTASC at either of these main functions and > simply swallow the MMC-compiled swf file. > > // SomeApplication.main(); > SomeApplicationRunner.main(); > > I hope that helps. > > > Luke Bayes > www.asunit.org > > > On 12/29/06, Marcelo de Moraes Serpa wrote: > > > > Hi Luke, thanks for the reply :) > > > > It is still not clear to me the role of MovieClip classes on asunit unit > > tests. From what I've been reading about Unit Testing so far, I can > > understand that visual entities should not be unit tested directly. Instead, > > the business classes that are used by it should be tested and I don't think > > business classes should inherit MovieClip (am I misunderstanding something > > here?). > > > > But let's say I really want to instantiate a MovieClip class on my unit > > test. The XUL UI feature you described is for creating mock objects for > > MovieClip classes, right? I'm asking this becouse it would be too much of a > > stress to try to instantiate a regular "non-serializable" MovieClip class as > > it depends on assets that are not present on the test swf library (and > > should not be present, I'm almost sure!). > > > > Cheers, > > > > Marcelo. > > > > > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share > your > opinions on IT & business topics through brief surveys - and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > > _______________________________________________ > Asunit-users mailing list > Asu...@li... > https://lists.sourceforge.net/lists/listinfo/asunit-users > > > |
|
From: Luke B. <lb...@gm...> - 2006-12-29 19:19:06
|
Hey Marcelo, There are a couple of issues you're talking about here, I'm going to restate them a little differently, please let me know if this is inaccurate. 1) Should I ever write a unit test for a visual entity? Yes. There are definitely times when views have code. Even using MVC, the view is responsible for some work and unit testing can verify that this work is being done as expected. 2) How do I structure an application for unit testing? Ali and I spent a considerable amount of time thinking about this problem, and after quite a bit of trial and error, we realized that one of the most important aspects to testing is that the environment your test harness operates in should be as nearly identical to your production environment as possible. This includes library assets, frameworks, etc... For example, Macromedia's components manipulate some core object prototypes, add functions to _global and place assets on _root in a very high level which affects our ability to use _root.getNextHighestDepth(). IF we are using components in our application, but fail to load that library into our test swf, we will see behaviors in production that are very different from those that we find in our tests. We generally try to avoid using a fla file if at all possible, but if we are forced to use a .fla file for a project, the most important thing that we do, is avoid doing any real work on the main timeline. If we have some animation or some frame-based work that needs done, we put it into a MovieClip. The main timeline of our .fla files generally has one line of ActionScript. This line is usually switched from running our application main function to running our test suite main function. This has the added benefit of allowing us to point MTASC at either of these main functions and simply swallow the MMC-compiled swf file. // SomeApplication.main(); SomeApplicationRunner.main(); I hope that helps. Luke Bayes www.asunit.org On 12/29/06, Marcelo de Moraes Serpa wrote: > > Hi Luke, thanks for the reply :) > > It is still not clear to me the role of MovieClip classes on asunit unit > tests. From what I've been reading about Unit Testing so far, I can > understand that visual entities should not be unit tested directly. Instead, > the business classes that are used by it should be tested and I don't think > business classes should inherit MovieClip (am I misunderstanding something > here?). > > But let's say I really want to instantiate a MovieClip class on my unit > test. The XUL UI feature you described is for creating mock objects for > MovieClip classes, right? I'm asking this becouse it would be too much of a > stress to try to instantiate a regular "non-serializable" MovieClip class as > it depends on assets that are not present on the test swf library (and > should not be present, I'm almost sure!). > > Cheers, > > Marcelo. > > |