Merge commit 'd90867218312b97113ce7c50c5232f6e5ceee9be'
diff --git a/ApproveSDK.xml b/ApproveSDK.xml index 08134b7..903655d 100644 --- a/ApproveSDK.xml +++ b/ApproveSDK.xml
@@ -54,10 +54,10 @@ <property name="src.rat.report" value="${basedir}/rat-report-src.txt"/> <property name="bin.rat.report" value="${basedir}/rat-report-bin.txt"/> - <property name="apache.rat.jar" value="apache-rat-0.11.jar" /> - <property name="apache.rat.tasks.jar" value="apache-rat-tasks-0.11.jar" /> - <property name="apache.rat.url" value="http://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat/0.11" /> - <property name="apache.rat.tasks.url" value="http://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat-tasks/0.11" /> + <property name="apache.rat.jar" value="apache-rat-0.12.jar" /> + <property name="apache.rat.tasks.jar" value="apache-rat-tasks-0.12.jar" /> + <property name="apache.rat.url" value="http://central.maven.org/maven2/org/apache/rat/apache-rat/0.12" /> + <property name="apache.rat.tasks.url" value="http://central.maven.org/maven2/org/apache/rat/apache-rat-tasks/0.12" /> <property file="${basedir}/approvesdk.properties"/> @@ -325,6 +325,7 @@ <exclude name="licenseParts/NOTICE.asc"/> <exclude name="licenseParts/NOTICE.base"/> <exclude name="licenseParts/NOTICE.pb"/> + <exclude name="licenseParts/saxon9-NOTICES/*"/> <exclude name="modules/thirdparty/batik/lib/**/LICENSE*.txt"/> <exclude name="modules/thirdparty/batik/lib/**/README*.txt"/> <exclude name="frameworks/projects/flatspark/src/flatspark/assets/fonts/**/OFL.txt"/>
diff --git a/GIT-TEST.txt b/GIT-TEST.txt index 8755d36..59972d6 100644 --- a/GIT-TEST.txt +++ b/GIT-TEST.txt
@@ -1,5 +1,5 @@ ο»ΏHope that it works and I'll be ready to change the world ;-) [okrueger] - + Test by piotrz :) junheider is Top Posting this fileοΏ½people hate this on mailing lists.
diff --git a/KEYS b/KEYS index 6651922..b9f884f 100644 --- a/KEYS +++ b/KEYS
@@ -356,3 +356,119 @@ f/WyocyIyPkr7HH0xI7PLn0= =nsEL -----END PGP PUBLIC KEY BLOCK----- +pub rsa4096/EDF6613E 2016-09-09 +uid [ultimate] Josh Tynjala (CODE SIGNING KEY) <joshtynjala@apache.org> +sig 3 EDF6613E 2016-09-09 Josh Tynjala (CODE SIGNING KEY) <joshtynjala@apache.org> +sub rsa4096/D5780FEF 2016-09-09 +sig EDF6613E 2016-09-09 Josh Tynjala (CODE SIGNING KEY) <joshtynjala@apache.org> + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2 + +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 +CR1nUan0cN8sLesf4hK5RUWpX6ww0g== +=mfLU +-----END PGP PUBLIC KEY BLOCK----- + +pub 4096R/05061FC8 2017-06-17 +Key fingerprint = 4499 8F3E 2427 27E9 4C4B ADEB 6B0A 7EC9 0506 1FC8 +uid Piotr Zarzycki (CODE SIGNING KEY) <piotrz@apache.org> +sub 4096R/E7EF0C6D 2017-06-17 + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG 2.0.30 + +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 +ZGs7Ibn/LbgXcM6jdzDFLOHfulZ/ +=GBzo +-----END PGP PUBLIC KEY BLOCK-----
diff --git a/LICENSE b/LICENSE index 3faa057..3de99e1 100644 --- a/LICENSE +++ b/LICENSE
@@ -258,6 +258,9 @@ The Lato font is available under OFL. For details see frameworks/projects/flatspark/src/flatspark/assets/fonts/lato +The AwesomeUtils is available under MIT. For details +see frameworks/projects/flatspark/src/flatspark/utils/AwesomeUtils.as + This product includes a fork of Apache Batik which includes files available under the 2002 W3C Software license. For details, see modules/thirdparty/batik/LICENSE.W3C2002.
diff --git a/README b/README index 0bd9999..7aee7d1 100644 --- a/README +++ b/README
@@ -215,6 +215,10 @@ On Windows, download the Adobe Extension Manager from: http://download.macromedia.com/pub/dw_exchange/extension_manager/win/AdobeExtensionManager5All.zip + +On Windows 10, download the Adobe Extension Manager CS6 from: + + http://download.macromedia.com/pub/dw_exchange/extension_manager/win/AdobeExtensionManager6_0_8All.zip and set ADOBE_EXTENSION_MANAGER to the absolute path of 'Adobe Extension Manager CS5.exe'
diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 5aaadc3..81d4b72 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES
@@ -1,3 +1,45 @@ +Apache Flex 4.16.1 +================== + +AIR and Flash Player Support +---------------------------- +- Support Flash Player 21.0, 22.0, 23.0, 24.0, 25.0, 26.0 and 27.0 +- Support for AIR 21.0, 22.0, 23.0, 24.0, 25.0, 26.0 and 27.0 + +Bug Fixes +--------- +FLEX-35364 Flex installer.xml is failing occasionally +FLEX-35329 Initializing member variable/constant that is [Deprecated] + incorrectly throws extra warning +FLEX-35321 LayoutManager initializes components which are no longer on stage +FLEX-35267 Spark DataGrid's GridHeaderViewLayout.getHeaderIndexAt() returns wrong header index when leftPadding is comparable to a column's width +FLEX-27509 AdvancedListBase itemMaskFreeList is null + +Known Issues +------------ + +Adobe Flash Builder Integration + +Adobe Flash Builder 4.7 and Adobe Flash Builder 4.6 both contain a bug where, +when generating the .mxml file for a new project that uses Apache Flex SDK +4.10.0 or later Spark Application, Flash Builder will incorrectly insert the +attribute: + + layout="absolute" + +This results in a compile error in the new project. The remedy is to simply +remove the errant attribute. + +The following wiki page has been set up to contain the latest news on Adobe's +attempt to correct this problem: + + https://cwiki.apache.org/confluence/display/FLEX/Adobe+Flash+Builder+'New+Project'+Bug + +Adobe has provided a patch for Flash Builder 4.7 that resolves this issue: + + http://helpx.adobe.com/flash-builder/kb/flex-new-project-issue--.html + + Apache Flex 4.16.0 ==================
diff --git a/build.properties b/build.properties index 0ba13bb..fb505da 100644 --- a/build.properties +++ b/build.properties
@@ -18,8 +18,8 @@ ################################################################################ # flex-sdk-description values -release = Apache Flex 4.16.0 -release.version = 4.16.0 +release = Apache Flex 4.16.1 +release.version = 4.16.1 # override on command line with -Dbuild.number=999 or in local.properties build.number = 0
diff --git a/frameworks/build.xml b/frameworks/build.xml index 500a186..2e71195 100644 --- a/frameworks/build.xml +++ b/frameworks/build.xml
@@ -142,6 +142,7 @@ <antcall target="spark-test"/> <antcall target="advancedgrids-test"/> <antcall target="framework-test"/> + <antcall target="mx-test"/> </target> <target name="flex-config" depends="playerglobal-setswfversion" description="Copy the flex/air/airmobile config templates to flex/air/airmobile-config.xml and inject version numbers"> @@ -551,6 +552,9 @@ <target name="framework-test" description="Tests for 'framework' project"> <ant dir="${basedir}/projects/framework" target="test"/> </target> + <target name="mx-test" description="Tests for the 'mx' project"> + <ant dir="${basedir}/projects/mx" target="test"/> + </target> <target name="experimental" description="Clean build of experimental.swc"> <ant dir="${basedir}/projects/experimental"/>
diff --git a/frameworks/projects/advancedgrids/src/mx/core/Version.as b/frameworks/projects/advancedgrids/src/mx/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/advancedgrids/src/mx/core/Version.as +++ b/frameworks/projects/advancedgrids/src/mx/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/airframework/src/mx/core/Version.as b/frameworks/projects/airframework/src/mx/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/airframework/src/mx/core/Version.as +++ b/frameworks/projects/airframework/src/mx/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/airspark/src/spark/core/Version.as b/frameworks/projects/airspark/src/spark/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/airspark/src/spark/core/Version.as +++ b/frameworks/projects/airspark/src/spark/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/apache/src/core/Version.as b/frameworks/projects/apache/src/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/apache/src/core/Version.as +++ b/frameworks/projects/apache/src/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/automation/src/mx/core/Version.as b/frameworks/projects/automation/src/mx/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/automation/src/mx/core/Version.as +++ b/frameworks/projects/automation/src/mx/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/automation_agent/src/mx/core/Version.as b/frameworks/projects/automation_agent/src/mx/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/automation_agent/src/mx/core/Version.as +++ b/frameworks/projects/automation_agent/src/mx/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/automation_air/src/mx/core/Version.as b/frameworks/projects/automation_air/src/mx/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/automation_air/src/mx/core/Version.as +++ b/frameworks/projects/automation_air/src/mx/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/automation_dmv/src/mx/core/Version.as b/frameworks/projects/automation_dmv/src/mx/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/automation_dmv/src/mx/core/Version.as +++ b/frameworks/projects/automation_dmv/src/mx/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/automation_flashflexkit/src/mx/core/Version.as b/frameworks/projects/automation_flashflexkit/src/mx/core/Version.as index 0b10511..9782bf9 100644 --- a/frameworks/projects/automation_flashflexkit/src/mx/core/Version.as +++ b/frameworks/projects/automation_flashflexkit/src/mx/core/Version.as
@@ -24,4 +24,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/automation_spark/src/mx/core/Version.as b/frameworks/projects/automation_spark/src/mx/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/automation_spark/src/mx/core/Version.as +++ b/frameworks/projects/automation_spark/src/mx/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/automation_spark/src/spark/core/Version.as b/frameworks/projects/automation_spark/src/spark/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/automation_spark/src/spark/core/Version.as +++ b/frameworks/projects/automation_spark/src/spark/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/charts/src/mx/core/Version.as b/frameworks/projects/charts/src/mx/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/charts/src/mx/core/Version.as +++ b/frameworks/projects/charts/src/mx/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/flatspark/src/flatspark/utils/ColorUtils.as b/frameworks/projects/flatspark/src/flatspark/utils/ColorUtils.as index 09f9cb2..e9007c3 100644 --- a/frameworks/projects/flatspark/src/flatspark/utils/ColorUtils.as +++ b/frameworks/projects/flatspark/src/flatspark/utils/ColorUtils.as
@@ -45,15 +45,10 @@ public static const Concrete:uint = 0x95A5A6; public static const Asbestos:uint = 0x7F8C8D; - public function ColorUtils() - { - - } - public static function ButtonColor(brand:int, estado:State):uint { // All the possible colors - var cores:Array = new Array( + var cores:Array = [ ButtonColorEnum.PrimaryUp, ButtonColorEnum.PrimaryHover, ButtonColorEnum.PrimaryDown, ButtonColorEnum.PrimaryDisabled, ButtonColorEnum.SuccessUp, ButtonColorEnum.SuccessHover, ButtonColorEnum.SuccessDown, ButtonColorEnum.SuccessDisabled, ButtonColorEnum.WarningUp, ButtonColorEnum.WarningHover, ButtonColorEnum.WarningDown, ButtonColorEnum.WarningDisabled, @@ -61,7 +56,7 @@ ButtonColorEnum.DefaultUp, ButtonColorEnum.DefaultHover, ButtonColorEnum.DefaultDown, ButtonColorEnum.DefaultDisabled, ButtonColorEnum.InfoUp, ButtonColorEnum.InfoHover, ButtonColorEnum.InfoDown, ButtonColorEnum.InfoDisabled, ButtonColorEnum.DangerUp, ButtonColorEnum.DangerHover, ButtonColorEnum.DangerDown, ButtonColorEnum.DangerDisabled - ); + ]; // Map all the allowed states var numeroEstado:int = 1; @@ -80,11 +75,8 @@ numeroEstado = 3; break; } - - var posicao:int = 1; - posicao = 4 * (brand - 1) + (numeroEstado - 1); - - return cores[posicao]; + + return cores[4 * (brand - 1) + (numeroEstado - 1)]; } } } \ No newline at end of file
diff --git a/frameworks/projects/framework/src/mx/core/FlexVersion.as b/frameworks/projects/framework/src/mx/core/FlexVersion.as index 08650af..21a99b3 100644 --- a/frameworks/projects/framework/src/mx/core/FlexVersion.as +++ b/frameworks/projects/framework/src/mx/core/FlexVersion.as
@@ -56,9 +56,23 @@ * @playerversion AIR 1.1 * @productversion Flex 3 */ - public static const CURRENT_VERSION:uint = 0x04100000; + public static const CURRENT_VERSION:uint = 0x04100001; - /** + /** + * The <code>compatibilityVersion</code> value of Flex 4.16.1, + * encoded numerically as a <code>uint</code>. + * Code can compare this constant against + * the <code>compatibilityVersion</code> + * to implement version-specific behavior. + * + * @langversion 3.0 + * @playerversion Flash 11 + * @playerversion AIR 3 + * @productversion Apache Flex 4.16.1 + */ + public static const VERSION_4_16_1:uint = 0x04100001; + + /** * The <code>compatibilityVersion</code> value of Flex 4.16, * encoded numerically as a <code>uint</code>. * Code can compare this constant against
diff --git a/frameworks/projects/framework/src/mx/core/Version.as b/frameworks/projects/framework/src/mx/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/framework/src/mx/core/Version.as +++ b/frameworks/projects/framework/src/mx/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/framework/src/mx/managers/LayoutManager.as b/frameworks/projects/framework/src/mx/managers/LayoutManager.as index 45395ac..131838e 100644 --- a/frameworks/projects/framework/src/mx/managers/LayoutManager.as +++ b/frameworks/projects/framework/src/mx/managers/LayoutManager.as
@@ -19,14 +19,10 @@ package mx.managers { -import flash.display.DisplayObject; -import flash.display.Sprite; import flash.display.Stage; import flash.events.Event; import flash.events.EventDispatcher; -import mx.core.ILayoutElement; -import mx.core.UIComponent; import mx.core.UIComponentGlobals; import mx.core.mx_internal; import mx.events.DynamicEvent; @@ -780,7 +776,7 @@ */ private function doPhasedInstantiation():void { - // trace(">>DoPhasedInstantation"); + // trace(">>DoPhasedInstantiation"); // If phasing, do only one phase: validateProperties(), // validateSize(), or validateDisplayList(). @@ -846,10 +842,14 @@ var obj:ILayoutManagerClient = ILayoutManagerClient(updateCompleteQueue.removeLargest()); while (obj) { - if (!obj.initialized && obj.processedDescriptors) - obj.initialized = true; - if (obj.hasEventListener(FlexEvent.UPDATE_COMPLETE)) - obj.dispatchEvent(new FlexEvent(FlexEvent.UPDATE_COMPLETE)); + if(obj.nestLevel) + { + if (!obj.initialized && obj.processedDescriptors) + obj.initialized = true; + if (obj.hasEventListener(FlexEvent.UPDATE_COMPLETE)) + obj.dispatchEvent(new FlexEvent(FlexEvent.UPDATE_COMPLETE)); + } + obj.updateCompletePendingFlag = false; obj = ILayoutManagerClient(updateCompleteQueue.removeLargest()); } @@ -927,7 +927,6 @@ var lastCurrentObject:ILayoutManagerClient = currentObject; var obj:ILayoutManagerClient; - var i:int = 0; var done:Boolean = false; var oldTargetLevel:int = targetLevel; @@ -1094,12 +1093,16 @@ obj = ILayoutManagerClient(updateCompleteQueue.removeLargestChild(target)); while (obj) { - if (!obj.initialized) - obj.initialized = true; - - if (obj.hasEventListener(FlexEvent.UPDATE_COMPLETE)) - obj.dispatchEvent(new FlexEvent(FlexEvent.UPDATE_COMPLETE)); - obj.updateCompletePendingFlag = false; + if(obj.nestLevel) + { + if (!obj.initialized) + obj.initialized = true; + + if (obj.hasEventListener(FlexEvent.UPDATE_COMPLETE)) + obj.dispatchEvent(new FlexEvent(FlexEvent.UPDATE_COMPLETE)); + } + + obj.updateCompletePendingFlag = false; obj = ILayoutManagerClient(updateCompleteQueue.removeLargestChild(target)); } }
diff --git a/frameworks/projects/framework/tests/mx/managers/LayoutManager_FLEX_35321_Tests.as b/frameworks/projects/framework/tests/mx/managers/LayoutManager_FLEX_35321_Tests.as new file mode 100644 index 0000000..1c830f4 --- /dev/null +++ b/frameworks/projects/framework/tests/mx/managers/LayoutManager_FLEX_35321_Tests.as
@@ -0,0 +1,295 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.managers { + import flash.events.Event; + import flash.events.EventDispatcher; + + import mx.core.UIComponentGlobals; + import mx.core.mx_internal; + import mx.events.FlexEvent; + + import org.flexunit.assertThat; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.asserts.assertNull; + import org.flexunit.async.Async; + import org.fluint.uiImpersonation.UIImpersonator; + + use namespace mx_internal; + + public class LayoutManager_FLEX_35321_Tests + { + private static var noEnterFramesRemaining:int = NaN; + private static const _finishNotifier:EventDispatcher = new EventDispatcher(); + + private var _objectWhichIsRemovedAtValidation:SomeComponent; + private var _creationCompleteCalls:int; + + [Before] + public function setUp():void + { + _creationCompleteCalls = 0; + _objectWhichIsRemovedAtValidation = new SomeComponent(); + _objectWhichIsRemovedAtValidation.addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete); + UIImpersonator.addElement(_objectWhichIsRemovedAtValidation); + } + + [After] + public function tearDown():void + { + UIImpersonator.removeAllChildren(); + _objectWhichIsRemovedAtValidation = null; + } + + + //-------------------------------------------------------------------------- + // + // Test method + // + //-------------------------------------------------------------------------- + + [Test] + public function test_object_removed_from_stage_via_code_is_not_initialized():void + { + //given + UIComponentGlobals.mx_internal::layoutManager.usePhasedInstantiation = false; + _objectWhichIsRemovedAtValidation.removeFromStageOnValidateProperties = true; + + //when + _objectWhichIsRemovedAtValidation.invalidateProperties(); + _objectWhichIsRemovedAtValidation.invalidateSize(); + _objectWhichIsRemovedAtValidation.invalidateDisplayList(); + _objectWhichIsRemovedAtValidation.validateNow(); + + //then + then_assert_not_initialized(); + assert_validation_count(1, 0, 0); + } + + + + //-------------------------------------------------------------------------- + // + // Test method + // + //-------------------------------------------------------------------------- + + [Test(async, timeout=500)] + public function test_object_removed_from_stage_via_user_action_is_not_initialized():void + { + //given + UIComponentGlobals.mx_internal::layoutManager.usePhasedInstantiation = true; + _objectWhichIsRemovedAtValidation.removeFromStageOnValidateProperties = false; + + //when + _objectWhichIsRemovedAtValidation.invalidateDisplayList(); + _objectWhichIsRemovedAtValidation.invalidateProperties(); + _objectWhichIsRemovedAtValidation.invalidateSize(); + + //then wait 1 frame + noEnterFramesRemaining = 1; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_remove_from_stage_via_callLater, 300, {nextStep:then_assert_not_initialized_but_partially_validated, afterNumFrames:3}); + } + + + + + //-------------------------------------------------------------------------- + // + // Test method + // + //-------------------------------------------------------------------------- + + [Test(async, timeout=750)] + public function test_object_removed_from_stage_then_readded_is_initialized_once():void + { + //given + UIComponentGlobals.mx_internal::layoutManager.usePhasedInstantiation = true; + _objectWhichIsRemovedAtValidation.removeFromStageOnValidateProperties = false; + + //when + _objectWhichIsRemovedAtValidation.invalidateDisplayList(); + _objectWhichIsRemovedAtValidation.invalidateProperties(); + _objectWhichIsRemovedAtValidation.invalidateSize(); + + //then wait 1 frame + noEnterFramesRemaining = 1; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_remove_from_stage_via_callLater, 300, {nextStep:then_readd_object, afterNumFrames:1}); + } + + private function then_readd_object(event:Event, passThroughData:Object):void + { + //then + assertNull("The object was actually not removed from stage. Huh?", _objectWhichIsRemovedAtValidation.parent); + + //when + UIImpersonator.addElement(_objectWhichIsRemovedAtValidation); + + //then wait 3 frames, to make sure validation is done + noEnterFramesRemaining = 3; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_assert_one_initialization_only, 400); + } + + private function then_assert_one_initialization_only(event:Event, passThroughData:Object):void + { + //then + assertNotNull("The object should be on stage...", _objectWhichIsRemovedAtValidation.parent); + assertThat("If it's on stage, the nestLevel should be positive", _objectWhichIsRemovedAtValidation.nestLevel > 0); + assertEquals("When validation is interrupted half-way it should be complete once the object is re-added to stage", 1, _creationCompleteCalls); + assert_validation_count(2, 2, 1); + } + + + //-------------------------------------------------------------------------- + // + // Shared test methods + // + //-------------------------------------------------------------------------- + + private function then_remove_from_stage_via_callLater(event:Event, passThroughData:Object):void + { + //then + assertEquals("The first validation step should have completed by now", 1, _objectWhichIsRemovedAtValidation.numValidatePropertiesCalls); + assertEquals("But not validateSize()", 0, _objectWhichIsRemovedAtValidation.numValidateSizeCalls); + assertEquals("Nor validateDisplayList()", 0, _objectWhichIsRemovedAtValidation.numValidateDisplayListCalls); + + //given + const whereToGoNext:Function = passThroughData.nextStep as Function; + const afterHowManyFrames:int = passThroughData.afterNumFrames as int; + + //when + _objectWhichIsRemovedAtValidation.pretendUserAskedForComponentRemovalInNextFrame(); + + //then wait + noEnterFramesRemaining = afterHowManyFrames; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, whereToGoNext, 300); + } + + private function then_assert_not_initialized(event:Event = null, passThroughData:Object = null):void + { + //then + assertNull("The object was actually not removed from stage. Huh?", _objectWhichIsRemovedAtValidation.parent); + assertEquals("Yep, this is the bug. Why call initialized=true on an object that's not on stage?", 0, _creationCompleteCalls); + } + + private function then_assert_not_initialized_but_partially_validated(event:Event = null, passThroughData:Object = null):void + { + //then + then_assert_not_initialized(event, passThroughData); + assert_validation_count(1, 1, 0); + } + + private function assert_validation_count(numPropertiesValidations:int = 1, numSizeValidations:int = 1, numDisplayListValidations:int = 1):void + { + //then + assertEquals("Properties should have been validated", numPropertiesValidations, _objectWhichIsRemovedAtValidation.numValidatePropertiesCalls); + assertEquals("Size should have been validated", numSizeValidations, _objectWhichIsRemovedAtValidation.numValidateSizeCalls); + assertEquals("Display list should have been validated", numDisplayListValidations, _objectWhichIsRemovedAtValidation.numValidateDisplayListCalls); + } + + + + private static function onEnterFrame(event:Event):void + { + if(!--noEnterFramesRemaining) + { + UIImpersonator.testDisplay.removeEventListener(Event.ENTER_FRAME, onEnterFrame); + _finishNotifier.dispatchEvent(new Event(Event.COMPLETE)); + } + } + + private function onCreationComplete(event:FlexEvent):void + { + _creationCompleteCalls++; + } + } +} + +import mx.core.IVisualElementContainer; +import mx.core.UIComponent; + +class SomeComponent extends UIComponent +{ + private var _removeFromStageOnValidateProperties:Boolean = false; + private var _numValidatePropertiesCalls:int = 0; + private var _numValidateSizeCalls:int = 0; + private var _numValidateDisplayListCalls:int = 0; + + override public function validateProperties():void + { + super.validateProperties(); + _numValidatePropertiesCalls++; + if(_removeFromStageOnValidateProperties) + removeFromStage(); + } + + override public function validateSize(recursive:Boolean = false):void + { + super.validateSize(recursive); + _numValidateSizeCalls++; + } + + override public function validateDisplayList():void + { + super.validateDisplayList(); + _numValidateDisplayListCalls++; + } + + private function removeFromStage():void + { + if(this.parent) + { + if(this.parent is IVisualElementContainer) + IVisualElementContainer(this.parent).removeElement(this); + else + this.parent.removeChild(this); + } + } + + public function pretendUserAskedForComponentRemovalInNextFrame():void + { + callLater(removeFromStage); + } + + public function set removeFromStageOnValidateProperties(value:Boolean):void + { + _removeFromStageOnValidateProperties = value; + } + + public function get numValidateDisplayListCalls():int + { + return _numValidateDisplayListCalls; + } + + public function get numValidateSizeCalls():int + { + return _numValidateSizeCalls; + } + + public function get numValidatePropertiesCalls():int + { + return _numValidatePropertiesCalls; + } +} \ No newline at end of file
diff --git a/frameworks/projects/mx/build.xml b/frameworks/projects/mx/build.xml index f1ad0ad..259c7b6 100644 --- a/frameworks/projects/mx/build.xml +++ b/frameworks/projects/mx/build.xml
@@ -229,4 +229,10 @@ <delete dir="${FLEX_HOME}/tempDoc" failonerror="false" includeEmptyDirs="true"/> <delete file="${basedir}/bundles/en_US/packages.dita" failonerror="false"/> </target> + + <target name="test" description="Runs the FlexUnit tests for this project"> + <ant antfile="${FLEX_HOME}/flexunit-tests.xml"> + <property name="project.root" value="${basedir}"/> + </ant> + </target> </project>
diff --git a/frameworks/projects/mx/src/mx/controls/Tree.as b/frameworks/projects/mx/src/mx/controls/Tree.as index 5f9215a..5bf874f 100644 --- a/frameworks/projects/mx/src/mx/controls/Tree.as +++ b/frameworks/projects/mx/src/mx/controls/Tree.as
@@ -1783,7 +1783,7 @@ // is the item on screen? if (visibleData[uid]) { - //find the rowindex of the row after the open thats opening/closing + //find the row index of the first row after the one that's opening/closing var n:int = listItems.length; for (rowIndex = 0; rowIndex < n; rowIndex++) {
diff --git a/frameworks/projects/mx/src/mx/controls/treeClasses/HierarchicalCollectionView.as b/frameworks/projects/mx/src/mx/controls/treeClasses/HierarchicalCollectionView.as index 5f357b0..59fe7e8 100644 --- a/frameworks/projects/mx/src/mx/controls/treeClasses/HierarchicalCollectionView.as +++ b/frameworks/projects/mx/src/mx/controls/treeClasses/HierarchicalCollectionView.as
@@ -267,7 +267,7 @@ var modelCursor:IViewCursor = treeData.createCursor(); if (modelCursor.beforeFirst) { - // indicates that an IPE occured on the first item + // indicates that an IPE occurred on the first item return treeData.length; } while (!modelCursor.afterLast) @@ -315,8 +315,7 @@ parentMap[uid] = parent; if (node != null && openNodes[uid] && - dataDescriptor.isBranch(node, treeData) && - dataDescriptor.hasChildren(node, treeData)) + dataDescriptor.isBranch(node, treeData)) { childNodes = getChildren(node); if (childNodes != null) @@ -432,7 +431,7 @@ /** * @private - * delegate getchildren in order to add event listeners for nested collections + * delegate getChildren in order to add event listeners for nested collections */ private function getChildren(node:Object):ICollectionView {
diff --git a/frameworks/projects/mx/src/mx/core/Version.as b/frameworks/projects/mx/src/mx/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/mx/src/mx/core/Version.as +++ b/frameworks/projects/mx/src/mx/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/mx/tests/mx/controls/Tree_FLEX_18746_Collection_Length_Tests.as b/frameworks/projects/mx/tests/mx/controls/Tree_FLEX_18746_Collection_Length_Tests.as new file mode 100644 index 0000000..4b32a32 --- /dev/null +++ b/frameworks/projects/mx/tests/mx/controls/Tree_FLEX_18746_Collection_Length_Tests.as
@@ -0,0 +1,220 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.controls { + import flash.events.Event; + import flash.events.EventDispatcher; + + import mx.collections.ArrayCollection; + import mx.core.mx_internal; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.async.Async; + import org.fluint.uiImpersonation.UIImpersonator; + + use namespace mx_internal; + + public class Tree_FLEX_18746_Collection_Length_Tests + { + private static var noEnterFramesToWait:int = NaN; + private static const _finishNotifier:EventDispatcher = new EventDispatcher(); + + private static var _sut:Tree_; + private static var Sam:TreeItem; + private static var Ana:TreeItem; + private static var Jenny:TreeItem; + private static var Marc:TreeItem; + private static var parentJill:TreeItem; + private static var parentJohn:TreeItem; + + + [Before] + public function setUp():void + { + Sam = new TreeItem("Sam"); + Ana = new TreeItem("Ana"); + Jenny = new TreeItem("Jenny"); + Marc = new TreeItem("Marc"); + + _sut = new Tree_(); + _sut.width = 200; + _sut.height = 200; + + UIImpersonator.addChild(_sut); + } + + [After] + public function tearDown():void + { + UIImpersonator.removeAllChildren(); + _sut = null; + } + + + [Test(async, timeout=300)] + public function test_opening_closing_with_both_parents_having_at_least_one_child():void + { + //given + parentJill = new TreeItem("Jill", new ArrayCollection([Marc])); + parentJohn = new TreeItem("John", new ArrayCollection([Sam])); + + const dataProvider:ArrayCollection = new ArrayCollection(); + dataProvider.addItem(parentJill); + dataProvider.addItem(parentJohn); + + //when + _sut.dataProvider = dataProvider; + + //then wait a few frames + noEnterFramesToWait = 2; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_expand_and_contract, 250); + } + + [Test(async, timeout=300)] + public function test_opening_closing_with_Jill_having_no_children_to_begin_with():void + { + //given + parentJill = new TreeItem("Jill", new ArrayCollection()); + parentJohn = new TreeItem("John", new ArrayCollection([Sam])); + + const dataProvider:ArrayCollection = new ArrayCollection(); + dataProvider.addItem(parentJill); + dataProvider.addItem(parentJohn); + + //when + _sut.dataProvider = dataProvider; + + //then wait a few frames + noEnterFramesToWait = 2; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_expand_and_contract, 250); + } + + private static function then_expand_and_contract(event:Event, passThroughData:Object):void + { + //given + var currentLength:int = _sut.collectionLength_; //current length is correct + + //then + assertEquals(2, currentLength); + + //when + _sut.expandItem(parentJohn, true, false, true); + currentLength += parentJohn.children.length; + + //then + assertEquals(currentLength, _sut.collectionLength_); + + //when + _sut.expandItem(parentJill, true, false, true); + currentLength += parentJill.children.length; + + //then + assertEquals(currentLength, _sut.collectionLength_); + + //when + parentJohn.children.addItem(Jenny); + currentLength += 1; + + //then + assertEquals(currentLength, _sut.collectionLength_); + + //when + _sut.expandItem(parentJohn, false, false, true); + currentLength -= parentJohn.children.length; + + //then + assertEquals(currentLength, _sut.collectionLength_); + + //when + parentJill.children.addItem(Ana); + currentLength += 1; + + //then + assertEquals(currentLength, _sut.collectionLength_); + } + + + private static function onEnterFrame(event:Event):void + { + if(!--noEnterFramesToWait) + { + UIImpersonator.testDisplay.removeEventListener(Event.ENTER_FRAME, onEnterFrame); + _finishNotifier.dispatchEvent(new Event(Event.COMPLETE)); + } + } + } +} + +import mx.controls.Tree; +import mx.controls.treeClasses.HierarchicalCollectionView; + +class Tree_ extends Tree +{ + public function getHierarchicalCollection():HierarchicalCollectionView + { + return super.collection as HierarchicalCollectionView; + } + + public function get collectionLength_():int + { + return getHierarchicalCollection().length; + } +} + +import mx.collections.ArrayCollection; + +class TreeItem { + private var _label:String; + private var _children:ArrayCollection; + + public function TreeItem(label:String, children:ArrayCollection = null) + { + this.label = label; + this.children = children; + } + + [Bindable] + public function set label(label:String):void + { + _label = label; + } + + public function get label():String + { + return _label; + } + + [Bindable] + public function set children(children:ArrayCollection):void + { + _children = children; + } + + public function get children():ArrayCollection + { + return _children; + } + + public function toString():String + { + return "TreeItem{_label=" + String(_label) + "}"; + } +} \ No newline at end of file
diff --git a/frameworks/projects/mx/tests/mx/controls/Tree_FLEX_18746_Tests.as b/frameworks/projects/mx/tests/mx/controls/Tree_FLEX_18746_Tests.as new file mode 100644 index 0000000..38bd4db --- /dev/null +++ b/frameworks/projects/mx/tests/mx/controls/Tree_FLEX_18746_Tests.as
@@ -0,0 +1,146 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.controls { + import flash.events.Event; + import flash.events.EventDispatcher; + + import mx.collections.ArrayCollection; + import mx.core.mx_internal; + + import org.flexunit.assertThat; + import org.flexunit.async.Async; + import org.fluint.uiImpersonation.UIImpersonator; + + use namespace mx_internal; + + public class Tree_FLEX_18746_Tests + { + private static var noEnterFramesToWait:int = NaN; + private static const _finishNotifier:EventDispatcher = new EventDispatcher(); + + private static var _sut:Tree; + private static var child:Object = {label: "Item"}; + private static var parent0:Object; + private static var parent1:Object; + + + [Before] + public function setUp():void + { + _sut = new Tree(); + _sut.width = 200; + _sut.height = 200; + + parent0 = {label: "Folder 0", children: new ArrayCollection()}; + parent1 = {label: "Folder 1", children: new ArrayCollection([child])}; + + UIImpersonator.addChild(_sut); + } + + [After] + public function tearDown():void + { + UIImpersonator.removeAllChildren(); + _sut = null; + } + + + [Test(async, timeout=1000)] + public function test_closing_previously_opened_folder_with_0_children_without_animation_does_not_throw_fatal():void + { + //given + const dataProvider:ArrayCollection = new ArrayCollection(); + dataProvider.addItem(parent0); + dataProvider.addItem(parent1); + + //when + _sut.dataProvider = dataProvider; + + //then wait a few frames + noEnterFramesToWait = 2; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_expand_second_folder, 300, {useAnimation:false}); + } + + [Test(async, timeout=1000)] + public function test_closing_previously_opened_folder_with_0_children_using_animation_does_not_throw_fatal():void + { + //given + const dataProvider:ArrayCollection = new ArrayCollection(); + dataProvider.addItem(parent0); + dataProvider.addItem(parent1); + + //when + _sut.dataProvider = dataProvider; + + //then wait a few frames + noEnterFramesToWait = 2; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_expand_second_folder, 300, {useAnimation:true}); + } + + + private function then_expand_second_folder(event:Event, passThroughData:Object):void + { + //when + _sut.expandItem(parent1, true, passThroughData.useAnimation, true); + + //then wait a bit + noEnterFramesToWait = 5; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_move_child_to_first_parent_and_expand_it, 500, passThroughData); + } + + private function then_move_child_to_first_parent_and_expand_it(event:Event, passThroughData:Object):void + { + //then + assertThat(_sut.isItemOpen(parent1)); + + //when + ArrayCollection(parent1.children).removeItemAt(0); + _sut.expandItem(parent0, true, passThroughData.useAnimation, true); + ArrayCollection(parent0.children).addItem(child); + + //then wait a bit + noEnterFramesToWait = 1; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_contract_second_folder, 200, passThroughData); + } + + private static function then_contract_second_folder(event:Event, passThroughData:Object):void + { + //when + _sut.expandItem(parent1, false, passThroughData.useAnimation, true); + + //then no error was thrown + assertThat(true); + } + + + private static function onEnterFrame(event:Event):void + { + if(!--noEnterFramesToWait) + { + UIImpersonator.testDisplay.removeEventListener(Event.ENTER_FRAME, onEnterFrame); + _finishNotifier.dispatchEvent(new Event(Event.COMPLETE)); + } + } + } +} \ No newline at end of file
diff --git a/frameworks/projects/rpc/src/mx/core/Version.as b/frameworks/projects/rpc/src/mx/core/Version.as index 463469f..158844f 100644 --- a/frameworks/projects/rpc/src/mx/core/Version.as +++ b/frameworks/projects/rpc/src/mx/core/Version.as
@@ -22,4 +22,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/spark/src/spark/components/GridColumnHeaderGroup.as b/frameworks/projects/spark/src/spark/components/GridColumnHeaderGroup.as index 9d5b81d..63a0eb3 100644 --- a/frameworks/projects/spark/src/spark/components/GridColumnHeaderGroup.as +++ b/frameworks/projects/spark/src/spark/components/GridColumnHeaderGroup.as
@@ -782,7 +782,29 @@ { return (_visibleSortIndicatorIndices.indexOf(columnIndex) != -1); } - + + /** + * True if either of this GridColumnHeaderGroup's views contains the global + * coordinates in the event, or if they fall over this component's padding. + */ + public function containsMouseEvent(event:MouseEvent):Boolean + { + return containsGlobalCoordinates(new Point(event.stageX, event.stageY)); + } + + public function containsGlobalCoordinates(coordinates:Point):Boolean + { + var globalPosition:Point = localToGlobal(new Point(getLayoutBoundsX(), getLayoutBoundsY())); + var bounds:Rectangle = new Rectangle(globalPosition.x, globalPosition.y, getLayoutBoundsWidth(), getLayoutBoundsHeight()); + + return bounds.containsPoint(coordinates); + } + + public function areCoordinatesOverAHeaderView(coordinates:Point):Boolean + { + return getHeaderViewUnderGlobalCoordinates(coordinates) != null; + } + //-------------------------------------------------------------------------- // // Methods @@ -804,28 +826,28 @@ */ public function configureGridColumnHeaderViews():void { - const ghl:GridHeaderLayout = layout as GridHeaderLayout; - if (!ghl) + const headerLayout:GridHeaderLayout = layout as GridHeaderLayout; + if (!headerLayout) return; - if (ghl.centerGridColumnHeaderView == null) - ghl.centerGridColumnHeaderView = createGridColumnHeaderView(); + if (headerLayout.centerGridColumnHeaderView == null) + headerLayout.centerGridColumnHeaderView = createGridColumnHeaderView(); if (dataGrid.lockedColumnCount > 0) { - ghl.leftGridColumnHeaderView = createGridColumnHeaderView(); + headerLayout.leftGridColumnHeaderView = createGridColumnHeaderView(); } - else if (ghl.leftGridColumnHeaderView) + else if (headerLayout.leftGridColumnHeaderView) { - removeElement(ghl.leftGridColumnHeaderView); - ghl.leftGridColumnHeaderView = null; + removeElement(headerLayout.leftGridColumnHeaderView); + headerLayout.leftGridColumnHeaderView = null; } const gridLayout:GridLayout = dataGrid.grid.layout as GridLayout; - GridHeaderViewLayout(ghl.centerGridColumnHeaderView.layout).gridView = gridLayout.centerGridView; - if (ghl.leftGridColumnHeaderView) - GridHeaderViewLayout(ghl.leftGridColumnHeaderView.layout).gridView = gridLayout.leftGridView; + GridHeaderViewLayout(headerLayout.centerGridColumnHeaderView.layout).gridView = gridLayout.centerGridView; + if (headerLayout.leftGridColumnHeaderView) + GridHeaderViewLayout(headerLayout.leftGridColumnHeaderView.layout).gridView = gridLayout.leftGridView; } /** @@ -850,7 +872,6 @@ */ public function getHeaderIndexAt(x:Number, y:Number):int { - // TODO: fix this: x coordinate has to be adjusted const view:Group = getColumnHeaderViewAtX(x); return GridHeaderViewLayout(view.layout).getHeaderIndexAt(x, y); } @@ -1000,16 +1021,16 @@ * comparison is based strictly on the event's location and the GridViews' bounds. * The event's target can be anything. */ - private function mouseEventHeaderView(event:MouseEvent):GridColumnHeaderView + private function getHeaderViewUnderGlobalCoordinates(globalCoordinates:Point):GridColumnHeaderView { const ghl:GridHeaderLayout = layout as GridHeaderLayout; - const centerGridColumnHeaderView:GridColumnHeaderView = GridColumnHeaderView(ghl.centerGridColumnHeaderView) - if (centerGridColumnHeaderView && centerGridColumnHeaderView.containsMouseEvent(event)) + const centerGridColumnHeaderView:GridColumnHeaderView = GridColumnHeaderView(ghl.centerGridColumnHeaderView); + if (centerGridColumnHeaderView && centerGridColumnHeaderView.containsGlobalPoint(globalCoordinates)) return centerGridColumnHeaderView; const leftGridColumnHeaderView:GridColumnHeaderView = GridColumnHeaderView(ghl.leftGridColumnHeaderView); - if (leftGridColumnHeaderView && leftGridColumnHeaderView.containsMouseEvent(event)) + if (leftGridColumnHeaderView && leftGridColumnHeaderView.containsGlobalPoint(globalCoordinates)) return leftGridColumnHeaderView; return null; @@ -1018,18 +1039,18 @@ // TODO: apologize for stashing the separatorIndex in headerCP.rowIndex private function eventToHeaderLocations(event:MouseEvent, headerCP:CellPosition, headerXY:Point):Boolean { - const view:Group = mouseEventHeaderView(event); + const stageXY:Point = new Point(event.stageX, event.stageY); + const view:Group = getHeaderViewUnderGlobalCoordinates(stageXY); if (!view) return false; - const stageXY:Point = new Point(event.stageX, event.stageY); const viewXY:Point = view.globalToLocal(stageXY); const viewLayout:GridHeaderViewLayout = view.layout as GridHeaderViewLayout; const gdv:GridDimensionsView = viewLayout.gridView.gridViewLayout.gridDimensionsView; const separatorIndex:int = viewLayout.getSeparatorIndexAt(viewXY.x, 0); headerCP.rowIndex = (separatorIndex != -1) ? separatorIndex + gdv.viewColumnIndex : -1; - headerCP.columnIndex = (separatorIndex == -1) ? viewLayout.getHeaderIndexAt(viewXY.x, 0) + gdv.viewColumnIndex : -1; + headerCP.columnIndex = (separatorIndex == -1) ? viewLayout.getHeaderIndexAt(viewXY.x, viewXY.y) + gdv.viewColumnIndex : -1; headerXY.x = viewXY.x + gdv.viewOriginX; headerXY.y = viewXY.y;
diff --git a/frameworks/projects/spark/src/spark/components/List.as b/frameworks/projects/spark/src/spark/components/List.as index c457c5b..d122821 100644 --- a/frameworks/projects/spark/src/spark/components/List.as +++ b/frameworks/projects/spark/src/spark/components/List.as
@@ -630,36 +630,7 @@ super.useVirtualLayout = value; } - //---------------------------------- - // dataProvider - //---------------------------------- - [Inspectable(category="Data")] - - /** - * @private - * - * @langversion 3.0 - * @playerversion Flash 10 - * @playerversion AIR 1.5 - * @productversion Flex 4 - */ - override public function set dataProvider(value:IList):void - { - // Uconditionally clear the selection, see SDK-21645. Can't wait - // to commit the selection because it could be set again before - // commitProperties runs and that selection gets lost. - if (!isEmpty(_proposedSelectedIndices) || !isEmpty(selectedIndices)) - { - _proposedSelectedIndices.length = 0; - multipleSelectionChanged = true; - invalidateProperties(); - UIComponentGlobals.layoutManager.validateClient(this, true); - } - super.dataProvider = value; - } - - //-------------------------------------------------------------------------- // // Properties
diff --git a/frameworks/projects/spark/src/spark/components/Scroller.as b/frameworks/projects/spark/src/spark/components/Scroller.as index 3ca9155..4db6528 100644 --- a/frameworks/projects/spark/src/spark/components/Scroller.as +++ b/frameworks/projects/spark/src/spark/components/Scroller.as
@@ -759,8 +759,8 @@ /** * @private - * These are the minimum and maximum scroll possitions allowed - * for both axes. They determine the points at which bounce and + * These are the minimum and maximum scroll positions allowed + * for both axes. They determine the points at which bounce and * pull occur. */ private var minVerticalScrollPosition:Number = 0;
diff --git a/frameworks/projects/spark/src/spark/components/gridClasses/GridColumnHeaderView.as b/frameworks/projects/spark/src/spark/components/gridClasses/GridColumnHeaderView.as index ee475ee..aecb7c2 100644 --- a/frameworks/projects/spark/src/spark/components/gridClasses/GridColumnHeaderView.as +++ b/frameworks/projects/spark/src/spark/components/gridClasses/GridColumnHeaderView.as
@@ -106,8 +106,13 @@ */ public function containsMouseEvent(event:MouseEvent):Boolean { - const eventStageX:Number = event.stageX; - const eventStageY:Number = event.stageY; + return containsGlobalPoint(new Point(event.stageX, event.stageY)); + } + + public function containsGlobalPoint(globalCoordinates:Point):Boolean + { + const stageX:Number = globalCoordinates.x; + const stageY:Number = globalCoordinates.y; const origin:Point = localToGlobal(zeroPoint); origin.x += horizontalScrollPosition; @@ -115,9 +120,11 @@ origin.x -= width; origin.y += verticalScrollPosition; - - return (eventStageX >= origin.x) && (eventStageY >= origin.y) && - (eventStageX < (origin.x + width)) && (eventStageY < (origin.y + height)); + + var headerViewContainsGlobalCoordinates:Boolean = (stageX >= origin.x) && (stageY >= origin.y) && + (stageX < (origin.x + width)) && (stageY < (origin.y + height)); + + return headerViewContainsGlobalCoordinates; } } } \ No newline at end of file
diff --git a/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensions.as b/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensions.as index ec0a003..9c975b2 100644 --- a/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensions.as +++ b/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensions.as
@@ -1183,28 +1183,31 @@ */ public function getColumnIndexAt(x:Number, y:Number):int { - var cur:Number = x; + var current:Number = x; var i:int; - + + if(current < 0) + return -1; + for (i = 0; i < _columnCount; i++) { - var temp:Number = _columnWidths[i]; + var columnWidth:Number = _columnWidths[i]; // fall back on typical widths if the actual width isn't set. - if (isNaN(temp)) + if (isNaN(columnWidth)) { - temp = typicalCellWidths[i]; - if (temp == 0) // invisible column + columnWidth = typicalCellWidths[i]; + if (columnWidth == 0) // invisible column continue; } // fall back on defaultColumnWidth - if (isNaN(temp)) - temp = defaultColumnWidth; + if (isNaN(columnWidth)) + columnWidth = defaultColumnWidth; - cur -= temp + columnGap; + current -= columnWidth + columnGap; - if (cur < 0) + if (current < 0) return i; }
diff --git a/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensionsView.as b/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensionsView.as index fe7b55a..e5444a6 100644 --- a/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensionsView.as +++ b/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensionsView.as
@@ -225,9 +225,9 @@ return rowIndex >= 0 ? rowIndex : -1; } - public function getColumnIndexAt(viewX:Number, viewY:Number):int + public function getColumnIndexAt(localX:Number, localY:Number):int { - const columnIndex:int = gridDimensions.getColumnIndexAt(viewX + viewOriginX, viewY + viewOriginY) - viewColumnIndex; + const columnIndex:int = gridDimensions.getColumnIndexAt(localX + viewOriginX, localY + viewOriginY) - viewColumnIndex; return columnIndex >= 0 ? columnIndex : -1; }
diff --git a/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderViewLayout.as b/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderViewLayout.as index 2d98b89..9432c0a 100644 --- a/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderViewLayout.as +++ b/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderViewLayout.as
@@ -500,33 +500,25 @@ */ public function getHeaderIndexAt(x:Number, y:Number):int { - return gridView.gridViewLayout.gridDimensionsView.getColumnIndexAt(x, y); - - // TODO: restore the special case handling below - /* - const gridColumnHeaderGroup:GridColumnHeaderGroup = this.gridColumnHeaderGroup; - const grid:Grid = this.grid; - const columnsView:IList = this.columnsView; - - if (!gridColumnHeaderGroup || !grid || !columnsView) - return -1; - - const paddingLeft:Number = gridColumnHeaderGroup.getStyle("paddingLeft"); - const paddedX:Number = x + paddingLeft; - var columnIndex:int = grid.getColumnIndexAt(paddedX, 0); - - // Special case for the stretched renderer above the vertical scrollbar - // TODO (klin): Rethink this case if we change how the last header looks. - if (columnIndex < 0) + var headerIndex:int = -1; + var globalPoint:Point = gridColumnHeaderGroup.localToGlobal(new Point(x - horizontalScrollPosition, y)); + + if(gridColumnHeaderGroup.areCoordinatesOverAHeaderView(globalPoint)) { - const contentWidth:Number = gridColumnHeaderGroup.contentWidth; - const totalWidth:Number = horizontalScrollPosition + gridColumnHeaderGroup.width - gridColumnHeaderGroup.getStyle("paddingRight"); - if (paddedX >= contentWidth && paddedX < totalWidth) - columnIndex = grid.getPreviousVisibleColumnIndex(columnsView.length) + var paddingLeftStyle:Number = gridColumnHeaderGroup.getStyle("paddingLeft"); + var paddingLeft:Number = isNaN(paddingLeftStyle) ? 0 : paddingLeftStyle; + + headerIndex = gridView.gridViewLayout.gridDimensionsView.getColumnIndexAt(x - paddingLeft, y); + + if(headerIndex == -1) + { + //then the point is either over the right padding, over the width of the vertical + //scroll bar, or over the space between the last separator and the width of the grid + headerIndex = grid.getPreviousVisibleColumnIndex(columnsView.length); + } } - - return columnIndex; - */ + + return headerIndex; } /**
diff --git a/frameworks/projects/spark/src/spark/components/supportClasses/DropDownListBase.as b/frameworks/projects/spark/src/spark/components/supportClasses/DropDownListBase.as index aaba442..c80c2b4 100644 --- a/frameworks/projects/spark/src/spark/components/supportClasses/DropDownListBase.as +++ b/frameworks/projects/spark/src/spark/components/supportClasses/DropDownListBase.as
@@ -900,7 +900,7 @@ var proposedNewIndex:int = NO_SELECTION; var currentIndex:int; - if (isDropDownOpen) + if (isDropDownOpen && layout) { // Normalize the proposed index for getNavigationDestinationIndex currentIndex = userProposedSelectedIndex < NO_SELECTION ? NO_SELECTION : userProposedSelectedIndex; @@ -992,7 +992,6 @@ { event.preventDefault(); } - } /**
diff --git a/frameworks/projects/spark/src/spark/components/supportClasses/ListBase.as b/frameworks/projects/spark/src/spark/components/supportClasses/ListBase.as index e700d0d..fbe1050 100644 --- a/frameworks/projects/spark/src/spark/components/supportClasses/ListBase.as +++ b/frameworks/projects/spark/src/spark/components/supportClasses/ListBase.as
@@ -1877,9 +1877,9 @@ // We want to wait one frame after validation has occured before turning off // selection transitions again. We tried using dataGroup's updateComplete event listener, - // but because some validateNows() occur (before all of the event handling code has finished), - // this was occuring too early. We also tried just using callLater or ENTER_FRAME, but that - // occurs before the LayoutManager has run, so we add an ENTER_FRAME handler with a + // but because some validateNow() calls occur (before all of the event handling code has + // finished), this was occurring too early. We also tried just using callLater or ENTER_FRAME, + // but that occurs before the LayoutManager has run, so we add an ENTER_FRAME handler with a // low priority to make sure it occurs after the LayoutManager pass. systemManager.addEventListener(Event.ENTER_FRAME, allowSelectionTransitions_enterFrameHandler, false, -100); }
diff --git a/frameworks/projects/spark/src/spark/core/Version.as b/frameworks/projects/spark/src/spark/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/spark/src/spark/core/Version.as +++ b/frameworks/projects/spark/src/spark/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/spark/tests/spark/components/DropDownListBase_FLEX_35362_Tests.as b/frameworks/projects/spark/tests/spark/components/DropDownListBase_FLEX_35362_Tests.as new file mode 100644 index 0000000..1305fb2 --- /dev/null +++ b/frameworks/projects/spark/tests/spark/components/DropDownListBase_FLEX_35362_Tests.as
@@ -0,0 +1,79 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package spark.components { + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.KeyboardEvent; + import flash.ui.Keyboard; + + import org.flexunit.asserts.assertTrue; + import org.flexunit.async.Async; + import org.fluint.uiImpersonation.UIImpersonator; + + public class DropDownListBase_FLEX_35362_Tests { + private var _sut:DropDownList; + private static const NO_ENTER_FRAMES_TO_ALLOW:int = 2; + private static var noEnterFramesRemaining:int = NaN; + private static const _finishNotifier:EventDispatcher = new EventDispatcher(); + + [Before] + public function setUp():void + { + _sut = new DropDownList(); + } + + [After] + public function tearDown():void + { + _sut = null; + UIImpersonator.removeAllChildren(); + } + + [Test(async, timeout=1000)] + public function test_pressing_END_right_after_opening_doesnt_trigger_fatal():void + { + //given + UIImpersonator.addChild(_sut); + + noEnterFramesRemaining = NO_ENTER_FRAMES_TO_ALLOW; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_open_drop_down_and_press_key, 300); + } + + private function then_open_drop_down_and_press_key(event:Event, passThroughData:Object):void + { + //when + _sut.openDropDown(); + _sut.dispatchEvent(new KeyboardEvent(KeyboardEvent.KEY_DOWN, true, false, 0, Keyboard.END, 0, true, false, false, true, false)); + + //then - no fatal thrown + assertTrue(true); + } + + private static function onEnterFrame(event:Event):void + { + if(!--noEnterFramesRemaining) + { + UIImpersonator.testDisplay.removeEventListener(Event.ENTER_FRAME, onEnterFrame); + _finishNotifier.dispatchEvent(new Event(Event.COMPLETE)); + } + } + } +}
diff --git a/frameworks/projects/spark/tests/spark/components/List_FLEX_35306_Tests.as b/frameworks/projects/spark/tests/spark/components/List_FLEX_35306_Tests.as new file mode 100644 index 0000000..1780240 --- /dev/null +++ b/frameworks/projects/spark/tests/spark/components/List_FLEX_35306_Tests.as
@@ -0,0 +1,274 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package spark.components { + import flash.events.Event; + import flash.events.EventDispatcher; + + import mx.collections.ArrayCollection; + import mx.collections.IList; + import mx.core.mx_internal; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.async.Async; + import org.flexunit.runners.Parameterized; + import org.fluint.uiImpersonation.UIImpersonator; + + import spark.skins.spark.ListSkin; + + use namespace mx_internal; + + [RunWith("org.flexunit.runners.Parameterized")] + public class List_FLEX_35306_Tests + { + private static var foo:Parameterized; + + private static const NO_ENTER_FRAMES_TO_ALLOW:int = 4; + private static var noEnterFramesRemaining:int = NaN; + private static const _finishNotifier:EventDispatcher = new EventDispatcher(); + + private static var _sut:_ListWithMXMLBinding; + + private static var _hqRedmond:_HeadquarterVO; + private static var _hqSantaClara:_HeadquarterVO; + private static var _hqBerlin:_HeadquarterVO; + private static var _hqMunchen:_HeadquarterVO; + private static var _hqNewYork:_HeadquarterVO; + private static var _hqSantaMaria:_HeadquarterVO; + private static var _hqSantaDolores:_HeadquarterVO; + + [Bindable] + public var selectedCompany:_CompanyVO; + [Bindable] + public var potentialHeadquarters:IList; + + public static var models:Array; + { + models = [[createListOfCompaniesWithOnePotentialAddressEach()], [createListOfCompaniesWithMultiplePotentialAddresses()]]; + } + + [AfterClass] + public static function tearDownStatic():void + { + models = null; + } + + [Before] + public function setUp():void + { + _sut = new _ListWithMXMLBinding(); + _sut.container = this; + _sut.setStyle("skinClass", ListSkin); + _sut.requireSelection = true; + } + + [After] + public function tearDown():void + { + UIImpersonator.removeAllChildren(); + _sut = null; + } + + [Test(order=2, async, timeout=1000, dataProvider="models", description="this should run after the main test because it rewrites the model")] + public function test_double_binding(companies:IList):void + { + //given + const firstCompany:_CompanyVO = companies.getItemAt(0) as _CompanyVO; + const secondCompany:_CompanyVO = companies.getItemAt(1) as _CompanyVO; + const secondCompanyHQ:_HeadquarterVO = secondCompany.originalHeadquarter; + selectedCompany = firstCompany; + + UIImpersonator.addElement(_sut); + + //when 1 + selectedCompany = secondCompany; + potentialHeadquarters = secondCompany.potentialHeadquarters; + + //then 1 - wait some frames until there's a selection + noEnterFramesRemaining = NO_ENTER_FRAMES_TO_ALLOW; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_check_binding_from_bindable_var_to_list, 400, {companies:companies, expectedHQ:secondCompanyHQ}); + } + + private function then_check_binding_from_bindable_var_to_list(event:Event, passThroughData:Object):void + { + //given + const companies:IList = passThroughData.companies; + const expectedHQ:_HeadquarterVO = passThroughData.expectedHQ as _HeadquarterVO; + const thirdCompany:_CompanyVO = companies.getItemAt(2) as _CompanyVO; + + //then + assertEquals("The list's selected item didn't change (correctly?) when we changed the associated bindable variable!", expectedHQ, _sut.selectedItem); + + //given 2 + var extraHQ:_HeadquarterVO = new _HeadquarterVO("hello", "address"); + + //when 2 + thirdCompany.potentialHeadquarters.addItem(extraHQ); + potentialHeadquarters = thirdCompany.potentialHeadquarters; + selectedCompany = thirdCompany; + _sut.selectedItem = extraHQ; + + //then 2 - wait some frames until there's a selection + noEnterFramesRemaining = NO_ENTER_FRAMES_TO_ALLOW; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_check_binding_from_list_to_bindable_var, 400, {companies:companies, expectedHQ:extraHQ}); + } + + private function then_check_binding_from_list_to_bindable_var(event:Event, passThroughData:Object):void + { + //given + const companies:IList = passThroughData.companies as IList; + const expectedHQ:_HeadquarterVO = passThroughData.expectedHQ as _HeadquarterVO; + + //then 2 + assertEquals("The binding destination didn't change (correctly?) when we changed the list's selectedItem!", expectedHQ, selectedCompany.headquarter); + + //cleanup + const thirdCompany:_CompanyVO = companies.getItemAt(2) as _CompanyVO; + thirdCompany.potentialHeadquarters.removeItem(expectedHQ); + } + + + + + + [Test(order=1, async, timeout=1000, dataProvider="models")] + public function test_list_doesnt_rewrite_model(companies:IList):void + { + //given + const secondCompany:_CompanyVO = companies.getItemAt(1) as _CompanyVO; + + //when + selectedCompany = secondCompany; + potentialHeadquarters = secondCompany.potentialHeadquarters; + + UIImpersonator.addElement(_sut); + + //then - wait some frames until there's a selection + noEnterFramesRemaining = NO_ENTER_FRAMES_TO_ALLOW; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_change_dp_and_selected_item, 400, companies); + } + + private function then_change_dp_and_selected_item(event:Event, passThroughData:Object):void + { + //given + const model:IList = passThroughData as IList; + const secondCompany:_CompanyVO = model.getItemAt(1) as _CompanyVO; + const thirdCompany:_CompanyVO = model.getItemAt(2) as _CompanyVO; + + //then + assertNotNull(secondCompany.headquarter); //HUH? + assertEquals("The selection should be " + secondCompany.headquarter.name + "!", secondCompany.originalHeadquarter, _sut.selectedItem); + + //when + selectedCompany = thirdCompany; + potentialHeadquarters = thirdCompany.potentialHeadquarters; + + //then - wait some frames until the selection has changed + noEnterFramesRemaining = NO_ENTER_FRAMES_TO_ALLOW; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, then_check_if_model_has_been_rewritten, 400, model); + } + + private static function then_check_if_model_has_been_rewritten(event:Event, passThroughData:Object):void + { + //given + const model:IList = passThroughData as IList; + const thirdCompany:_CompanyVO = model.getItemAt(2) as _CompanyVO; + const expectedHQ:_HeadquarterVO = thirdCompany.originalHeadquarter; + + //then + assertEquals("The selection should be " + expectedHQ.name + "!", expectedHQ, _sut.selectedItem); + + assertCompaniesHaveCorrectHQ(model); + assertNoCompanyHQWasRewritten(model); + } + + private static function assertCompaniesHaveCorrectHQ(companiesList:IList):void + { + for each(var company:_CompanyVO in companiesList) + { + assertEquals("The headquarter of " + company.name + " has been changed to an invalid value!", company.originalHeadquarter, company.headquarter); + } + } + + private static function assertNoCompanyHQWasRewritten(companiesList:IList):void + { + for each(var company:_CompanyVO in companiesList) + { + assertFalse("The headquarter of " + company.name + " has been rewritten, although with the correct value in the end", company.headquarterRewritten); + } + } + + private static function onEnterFrame(event:Event):void + { + if(!--noEnterFramesRemaining) + { + UIImpersonator.testDisplay.removeEventListener(Event.ENTER_FRAME, onEnterFrame); + _finishNotifier.dispatchEvent(new Event(Event.COMPLETE)); + } + } + + //-------------------------------------------------------------------------- + // + // Set up methods + // + //-------------------------------------------------------------------------- + + private static function createListOfCompaniesWithMultiplePotentialAddresses():IList + { + createHeadquartersIfNeeded(); + + var microsoft:_CompanyVO = new _CompanyVO("Microsoft", _hqRedmond, new ArrayCollection([_hqRedmond, _hqNewYork])); + var intel:_CompanyVO = new _CompanyVO("Intel", _hqSantaClara, new ArrayCollection([_hqSantaClara, _hqSantaMaria, _hqSantaDolores])); + var wv:_CompanyVO = new _CompanyVO("VW", _hqBerlin, new ArrayCollection([_hqBerlin, _hqMunchen])); + + return new ArrayCollection([microsoft, intel, wv]); + } + + private static function createListOfCompaniesWithOnePotentialAddressEach():IList + { + createHeadquartersIfNeeded(); + + var microsoft:_CompanyVO = new _CompanyVO("Microsoft", _hqRedmond, new ArrayCollection([_hqRedmond])); + var intel:_CompanyVO = new _CompanyVO("Intel", _hqSantaClara, new ArrayCollection([_hqSantaClara])); + var wv:_CompanyVO = new _CompanyVO("VW", _hqBerlin, new ArrayCollection([_hqBerlin])); + + return new ArrayCollection([microsoft, intel, wv]); + } + + private static function createHeadquartersIfNeeded():void + { + if(_hqRedmond) + return; + + _hqRedmond = new _HeadquarterVO("Redmond", "redmond address 123"); + _hqNewYork = new _HeadquarterVO("New York", "NY address 123"); + _hqSantaClara = new _HeadquarterVO("Santa Clara", "santa clara address 123"); + _hqSantaMaria = new _HeadquarterVO("Santa Maria", "santa maria address 123"); + _hqSantaDolores = new _HeadquarterVO("Santa Dolores", "santa dolores address 123"); + _hqBerlin = new _HeadquarterVO("Berlin", "berlin address 123"); + _hqMunchen = new _HeadquarterVO("Munchen", "munchen address 123"); + } + } +} \ No newline at end of file
diff --git a/frameworks/projects/spark/tests/spark/components/_CompanyVO.as b/frameworks/projects/spark/tests/spark/components/_CompanyVO.as new file mode 100644 index 0000000..7e21808 --- /dev/null +++ b/frameworks/projects/spark/tests/spark/components/_CompanyVO.as
@@ -0,0 +1,68 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package spark.components { + import mx.collections.ArrayCollection; + + [Bindable] + public class _CompanyVO + { + private var _headquarter:_HeadquarterVO; + private var _headquarterRewritten:Boolean = false; + private var _originalHeadquarter:_HeadquarterVO; + + public var name:String; + public var potentialHeadquarters:ArrayCollection; + + + public function _CompanyVO(name:String, headquarter:_HeadquarterVO, potentialHeadquarters:ArrayCollection) + { + this.name = name; + this._headquarter = headquarter; + this._originalHeadquarter = headquarter; + this.potentialHeadquarters = potentialHeadquarters; + } + + public function get headquarter():_HeadquarterVO + { + return _headquarter; + } + + public function set headquarter(value:_HeadquarterVO):void + { + _headquarterRewritten = true; + _headquarter = value; + } + + public function get headquarterRewritten():Boolean + { + return _headquarterRewritten; + } + + public function get originalHeadquarter():_HeadquarterVO + { + return _originalHeadquarter; + } + + public function toString():String + { + return "CompanyVO{name=" + String(name) + ", #hqs="+potentialHeadquarters.length+"}"; + } + } +}
diff --git a/frameworks/projects/spark/tests/spark/components/_HeadquarterVO.as b/frameworks/projects/spark/tests/spark/components/_HeadquarterVO.as new file mode 100644 index 0000000..ebfeb70 --- /dev/null +++ b/frameworks/projects/spark/tests/spark/components/_HeadquarterVO.as
@@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package spark.components { + [Bindable] + public class _HeadquarterVO { + public var name:String; + public var address:String; + + public function _HeadquarterVO(name:String, address:String) + { + this.name = name; + this.address = address; + } + + public function get label():String + { + return name; + } + + public function toString():String + { + return "HeadquarterVO{name=" + String(name) + "}"; + } + } +}
diff --git a/frameworks/projects/spark/tests/spark/components/_ListWithMXMLBinding.mxml b/frameworks/projects/spark/tests/spark/components/_ListWithMXMLBinding.mxml new file mode 100644 index 0000000..f2b24fb --- /dev/null +++ b/frameworks/projects/spark/tests/spark/components/_ListWithMXMLBinding.mxml
@@ -0,0 +1,41 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +<?xml version="1.0"?> +<s:List xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" + selectedItem="@{container.selectedCompany.headquarter}" + dataProvider="{container.potentialHeadquarters}"> + + <fx:Script> + <![CDATA[ + private var _container:Object; + + [Bindable] + public function get container():Object + { + return _container; + } + + public function set container(value:Object):void + { + _container = value; + } + ]]> + </fx:Script> +</s:List>
diff --git a/frameworks/projects/spark/tests/spark/components/gridClasses/GridHeaderViewLayout_FLEX_35260_Tests.as b/frameworks/projects/spark/tests/spark/components/gridClasses/GridHeaderViewLayout_FLEX_35260_Tests.as new file mode 100644 index 0000000..6677ea3 --- /dev/null +++ b/frameworks/projects/spark/tests/spark/components/gridClasses/GridHeaderViewLayout_FLEX_35260_Tests.as
@@ -0,0 +1,646 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package spark.components.gridClasses { + import flash.events.Event; + import flash.events.EventDispatcher; + + import flash.geom.Matrix; + import flash.geom.Point; + import flash.geom.Rectangle; + + import mx.collections.ArrayCollection; + + import org.flexunit.assertThat; + + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertTrue; + import org.flexunit.async.Async; + import org.flexunit.runners.Parameterized; + import org.fluint.uiImpersonation.UIImpersonator; + + import spark.components.DataGrid; + import spark.components.GridColumnHeaderGroup; + + /* + Example for two-column table (with no horizontal scroll): + + [pt]: GridColumnHeaderGroup padding top + [pl]: GridColumnHeaderGroup padding left + [lch]: still part of last column header, but beyond last column width + + b0: top-left corner of the data grid. Also, first column starts at this x-coordinate + b1: first column ends at this x-coordinate (but the first header usually doesn't, due to [pl]) + b2: second column ends at this x-coordinate (but the second header usually doesn't, due to [pl]) + ... + bx: last column ends at this x-coordinate + + c0: first column header starts at this x-coordinate + c1: first column header ends at this x-coordinate, separator starts at this x-coordinate, and + second column header (if it exists) starts at this x-coordinate + separator.width + c1: second column header ends at this x-coordinate, next separator (if it exists) starts at + this x-coordinate, and third column header (if it exists) starts at this x-coordinate + separator.width + ... + cx: last column header ends at this x-coordinate; last column separator starts at this x-coordinate + + d: table ends at this x-axis coordinate + e: top-left corner of header. If [pt] and [pl] are 0, this coincides with b0 + f: b0ttom-left corner of header. If [pb] and [pl] are 0, this coincides with g0 + + g0: header ends and grid starts at this y-coordinate + g1: first column ends at this x-coordinate and second column (if it exists) begins at this x-coordinate + g2: second column ends at this x-coordinate and third column (if it exists) begins at this x-coordinate + ... + gx: last column ends at this x-coordinate + + i: bottom-right point of last column header and x-coordinate at end of data grid + + And for each point we generate the 8 adjacent points: + (x+1, y), (x+1, y+1), (x+1, y-1), + (x-1, y), (x-1, y+1), (x-1, y-1), + (x, y-1), (x, y-1). For easier comprehension we mark them + using cardinal points: N, NE, E, SE, S, SW, W, NW. + ...and we check various boundaries against all of them + + a (0, 0) + ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ + βββββb0βββc0ββββββb1βββc1ββββββββββββββββββββββββββββb2ββc2βββββββββdβββββββ + ββββββ [pt] ββββββββ + ββββββ eβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ + ββββββ[pl]ββββINDEXβββββββββββββββββββββNAMEβββββββββββββββββ[lch]ββββββββββ + ββββββ fβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ + ββββββ [pb] ββββββββ + βββββg0βββββββββββg1βββββββββββββββββββββββββββββββββg2βββββββββββββiβββββββ + ββββββ 01 β John β ββββββββ + ββββββ 02 β Jane β ββββββββ + ββββββ 03 β Judy β ββββββββ + ββββββ 04 β James β ββββββββ + βββββββββββββββββββ©βββββββββββββββββββββββββββββββββββ©ββββββββββββββββββββββ + ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ + ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ + */ + + [RunWith("org.flexunit.runners.Parameterized")] + public class GridHeaderViewLayout_FLEX_35260_Tests + { + private static var foo:Parameterized; + private static const N:Matrix = new Matrix(1, 0, 0, 1, 0, -1); + private static const NE:Matrix = new Matrix(1, 0, 0, 1, 1, -1); + private static const E:Matrix = new Matrix(1, 0, 0, 1, 1, 0); + private static const SE:Matrix = new Matrix(1, 0, 0, 1, 1, 1); + private static const S:Matrix = new Matrix(1, 0, 0, 1, 0, 1); + private static const SW:Matrix = new Matrix(1, 0, 0, 1, -1, 1); + private static const W:Matrix = new Matrix(1, 0, 0, 1, -1, 0); + private static const NW:Matrix = new Matrix(1, 0, 0, 1, -1, -1); + private static const ITSELF:Matrix = new Matrix(1, 0, 0, 1, 0, 0); //the point, unmodified + private static const directions:Array = [ITSELF, N, NE, E, SE, S, SW, W, NW]; + + private static const ENTIRE_HEADER_RECTANGLE:String = "visibleHeaderRectangle"; //includes padding + private static const FIXED_HEADER_VIEW_RECTANGLE:String = "fixedHeaderViewRectangle"; + + private static const NO_ENTER_FRAMES_TO_ALLOW:int = 2; + + private static var _dataGrid:DataGrid; + private static const _finishNotifier:EventDispatcher = new EventDispatcher(); + + private var _keyRectangles:Array; + private var _keyPoints:Array; + private var _dimensions:Array; + private var _noEnterFramesRemaining:int = NaN; + + //@TODO add cases with fixed columns + //@TODO can the grid itself have padding? + //@TODO test with a columnGap as well + public static var allDimensions:Array = [ + /*x, y, width, header padding left, header padding top, header padding bottom, [column widths] */ + [[/*x=*/ 0, /*y=*/ 0, /*width=*/ 300, /*paddingLeft=*/ 5, /*paddingTop=*/ 0, /*paddingBottom=*/ 0, /*columnWidths=*/[25, 150]]], + [[/*x=*/ 10, /*y=*/ 0, /*width=*/ 300, /*paddingLeft=*/ 5, /*paddingTop=*/ 0, /*paddingBottom=*/ 5, /*columnWidths=*/[25, 150]]], + [[/*x=*/ 0, /*y=*/ 0, /*width=*/ 200, /*paddingLeft=*/ 5, /*paddingTop=*/ 0, /*paddingBottom=*/ 0, /*columnWidths=*/[80, 150]]], //horizontal scroll + [[/*x=*/ 0, /*y=*/ 0, /*width=*/ 100, /*paddingLeft=*/ 0, /*paddingTop=*/ 0, /*paddingBottom=*/ 0, /*columnWidths=*/[10, 110, 15]]], //horizontal scroll + [[/*x=*/ -5, /*y=*/-100, /*width=*/ 200, /*paddingLeft=*/ 25, /*paddingTop=*/ 12, /*paddingBottom=*/ 5, /*columnWidths=*/[100, 150]]] //horizontal scroll + ]; + + + [BeforeClass] + public static function setUpBeforeClass():void + { + _dataGrid = new DataGrid(); + _dataGrid.setStyle("borderVisible", false); //to not deal with the complications of Scroller.minViewportInset + UIImpersonator.addChild(_dataGrid); + } + + [AfterClass] + public static function tearDownAfterClass():void + { + UIImpersonator.removeAllChildren(); + + _dataGrid = null; + } + + [Before] + public function setUp():void + { + + } + + [After] + public function tearDown():void + { + _keyRectangles = null; + _keyPoints = null; + _dimensions = null; + } + + + [Test(dataProvider="allDimensions", async, timeout=3000)] + public function test_ltr(dimensions:Array):void + { + //given + _dataGrid.width = getWidth(dimensions); + _dataGrid.x = getX(dimensions); + _dataGrid.y = getY(dimensions); + + _dataGrid.columnHeaderGroup.setStyle("paddingLeft", getHeaderPaddingLeft(dimensions)); + _dataGrid.columnHeaderGroup.setStyle("paddingTop", getHeaderPaddingTop(dimensions)); + _dataGrid.columnHeaderGroup.setStyle("paddingBottom", getHeaderPaddingBottom(dimensions)); + + var gridColumns:Array = []; + for (var i:int = 0; i < getColumnWidths(dimensions).length; i++) + { + var column:GridColumn = new GridColumn(); + column.width = getColumnWidth(dimensions, i); + gridColumns.push(column); + } + _dataGrid.columns = new ArrayCollection(gridColumns); + + _dataGrid.columnHeaderGroup.invalidateDisplayList(); + _dataGrid.columnHeaderGroup.validateNow(); + _dataGrid.grid.validateNow(); + _dataGrid.validateNow(); + + _dimensions = dimensions; + _keyPoints = generateKeyPoints(_dataGrid); + _keyRectangles = generateKeyRectangles(); + + _noEnterFramesRemaining = NO_ENTER_FRAMES_TO_ALLOW; + UIImpersonator.testDisplay.addEventListener(Event.ENTER_FRAME, onEnterFrame); + Async.handleEvent(this, _finishNotifier, Event.COMPLETE, doTests, 3000); + } + + private function doTests(event:Event, passThroughData:Object):void + { + //then + //first, make sure that the dataGrid was rendered correctly + assertThat("The dataGrid has not yet been correctly rendered on stage", getActualHeaderHeight(_dataGrid) > 0); + + //test the assumption about the center column header view location + var centerGridViewLocation:Point = GridHeaderLayout(_dataGrid.columnHeaderGroup.layout).centerGridColumnHeaderView.localToGlobal(new Point(0, 0)); + assertTrue("The location of the centerGridColumnHeaderView does not reflect the columnHeaderGroup's padding rules! It's located at the global coordinates " + + centerGridViewLocation + ", but it should be at " + _keyPoints["e"], + centerGridViewLocation.equals(_keyPoints["e"])); + + forEachPointAndScrollLocation(assertAssumptionsAboutPoint); + } + + private function forEachPointAndScrollLocation(assertThat_:Function):void + { + _dataGrid.columnHeaderGroup.invalidateDisplayList(); + _dataGrid.columnHeaderGroup.validateNow(); + _dataGrid.grid.validateNow(); + _dataGrid.validateNow(); + + var maxScroll:Number = Math.max(1, getTotalColumnWidths(_dimensions) - getWidth(_dimensions) - getHeaderPaddingLeft(_dimensions)); + for (var i:int = 0; i < maxScroll; i++) + { + _dataGrid.grid.horizontalScrollPosition = i; + _dataGrid.columnHeaderGroup.invalidateDisplayList(); + _dataGrid.columnHeaderGroup.validateNow(); + _dataGrid.grid.validateNow(); + _dataGrid.validateNow(); + + for (var pointName:String in _keyPoints) + { + for (var j:int = 0; j < directions.length; j++) + { + assertThat_(getAdjacentPoint(_keyPoints[pointName], directions[j]), pointName, directions[j]); + _dataGrid.columnHeaderGroup.invalidateDisplayList(); + _dataGrid.columnHeaderGroup.validateNow(); + _dataGrid.grid.validateNow(); + _dataGrid.validateNow(); + } + } + } + } + + private function assertAssumptionsAboutPoint(point:Point, pointName:String, currentTransformation:Matrix):void + { + assertThatHeaderContainsPointOrNot(point, pointName, currentTransformation); + assertThatCoordinatesOverHeaderViewOrNot(point, pointName, currentTransformation); + assertThatHeaderIndexIsCorrect(point, pointName, currentTransformation); + assertThatColumnIndexIsCorrect(point, pointName, currentTransformation); + } + + private function assertThatHeaderContainsPointOrNot(point:Point, pointName:String, currentTransformation:Matrix):void + { + //when + var headerShouldContainThisPoint:Boolean = getHeaderShouldContainPointAssumption(point); + var doesHeaderContainThisPoint:Boolean = _sut.containsGlobalCoordinates(point); + const errorMessageHeaderContainsPoint:String = getHeaderContainsPointErrorMessage(pointName, currentTransformation, point, headerShouldContainThisPoint, doesHeaderContainThisPoint); + + //then + assertEquals(errorMessageHeaderContainsPoint, headerShouldContainThisPoint, doesHeaderContainThisPoint); + } + + private function assertThatCoordinatesOverHeaderViewOrNot(point:Point, pointName:String, currentTransformation:Matrix):void + { + //when + const visibleHeaderViewRectangle:Rectangle = getVisibleHeaderViewRectangle(getCurrentHScrollPosition()); + var shouldBeContainedInMainHeaderView:Boolean = getMainHeaderViewContainsPointAssumption(visibleHeaderViewRectangle, point); + var shouldBeContainedInFixedHeaderView:Boolean = getFixedHeaderViewContainsPointAssumption(point); + const shouldBeContainedInAHeaderView:Boolean = shouldBeContainedInMainHeaderView || shouldBeContainedInFixedHeaderView; + var actuallyContainedInAHeaderView:Boolean = _sut.areCoordinatesOverAHeaderView(point); + const errorMessageHeaderViewContainsPoint:String = getHeaderViewContainsPointErrorMessage(pointName, currentTransformation, point, shouldBeContainedInAHeaderView, actuallyContainedInAHeaderView, visibleHeaderViewRectangle); + + //then + assertEquals(errorMessageHeaderViewContainsPoint, shouldBeContainedInAHeaderView, actuallyContainedInAHeaderView); + } + + private function assertThatHeaderIndexIsCorrect(point:Point, pointName:String, currentTransformation:Matrix):void + { + //when + const visibleColumnHeaderRectangles:Array = getVisibleColumnHeaderRectangles(getCurrentHScrollPosition()); + var expectedHeaderIndex:int = getHeaderIndexAssumption(point, visibleColumnHeaderRectangles); + var actualHeaderIndex:int = getHeaderIndexAtGlobalPoint(point); + const errorMessageHeaderIndex:String = getHeaderIndexErrorMessage(pointName, currentTransformation, point, expectedHeaderIndex, actualHeaderIndex, visibleColumnHeaderRectangles); + + //then + assertEquals(errorMessageHeaderIndex, expectedHeaderIndex, actualHeaderIndex); + } + + private function assertThatColumnIndexIsCorrect(point:Point, pointName:String, currentTransformation:Matrix):void + { + //when + const visibleColumnRectangles:Array = getAllColumnRectangles(getCurrentHScrollPosition()); + var expectedColumnIndex:int = getColumnIndexAssumption(visibleColumnRectangles, point); + var actualColumnIndex:int = getColumnIndexAtGlobalPoint(point); + const errorMessageColumnIndex:String = getColumnIndexErrorMessage(pointName, currentTransformation, point, expectedColumnIndex, actualColumnIndex, visibleColumnRectangles); + + //then + assertEquals(errorMessageColumnIndex, expectedColumnIndex, actualColumnIndex); + } + + private function getHeaderIndexErrorMessage(pointName:String, direction:Matrix, transformedPoint:Point, expectedColumnHeaderIndex:int, actualColumnHeaderIndex:int, visibleColumnHeaderRectangles:Array):String + { + return "The point " + pointName + " transformed with Matrix " + direction + " (resulting in " + transformedPoint + ") should be " + + (expectedColumnHeaderIndex == -1 ? "outside any column header bounds" : "inside the column header with index " + expectedColumnHeaderIndex) + + " but was mistakenly found to be " + + (actualColumnHeaderIndex == -1 ? "outside any column header bounds" : "inside the column header with index " + actualColumnHeaderIndex) + + " given a horizontalScrollPosition of " + getCurrentHScrollPosition() + + "\n DEBUG INFO: visibleColumnHeaderRectangles=" + visibleColumnHeaderRectangles; + } + + private function getColumnIndexErrorMessage(pointName:String, direction:Matrix, transformedPoint:Point, expectedColumnHeaderIndex:int, actualColumnHeaderIndex:int, visibleColumnRectangles:Array):String + { + return "The point " + pointName + " transformed with Matrix " + direction + " (resulting in " + transformedPoint + ") should have its x value " + + (expectedColumnHeaderIndex == -1 ? "outside any column bounds" : "inside the column with index " + expectedColumnHeaderIndex) + + " but was mistakenly found to be " + + (actualColumnHeaderIndex == -1 ? "outside any column bounds" : "inside the column with index " + actualColumnHeaderIndex) + + " given a horizontalScrollPosition of " + getCurrentHScrollPosition() + + "\n DEBUG INFO: columnRectangles=" + visibleColumnRectangles; + } + + private function getHeaderContainsPointErrorMessage(pointName:String, direction:Matrix, transformedPoint:Point, shouldBeContainedInHeader:Boolean, isActuallyContainedInHeader:Boolean):String + { + return "The point " + pointName + " transformed with Matrix " + direction + " (resulting in " + transformedPoint + ") should be " + + (shouldBeContainedInHeader ? "within " : "outside ") + "the header bounds" + + " but was mistakenly found to be " + + (isActuallyContainedInHeader ? "within" : "outside") + + " given a horizontalScrollPosition of " + getCurrentHScrollPosition() + + "\n DEBUG INFO: header rectangle=" + entireHeaderRectangle; + } + + private function getHeaderViewContainsPointErrorMessage(pointName:String, direction:Matrix, transformedPoint:Point, shouldBeContainedInAHeaderView:Boolean, isActuallyContainedByAHeaderView:Boolean, visibleHeaderViewRectangle:Rectangle):String + { + return "The point " + pointName + " transformed with Matrix " + direction + " (resulting in " + transformedPoint + ") should be " + + (shouldBeContainedInAHeaderView ? "within " : "outside ") + "a header view" + + " but was mistakenly found to be " + + (isActuallyContainedByAHeaderView ? "within" : "outside") + + " given a horizontalScrollPosition of " + getCurrentHScrollPosition() + + "\n DEBUG INFO: rectangles of visible header views = " + fixedHeaderViewRectangle + "; " + visibleHeaderViewRectangle; + } + + private function getHeaderIndexAtGlobalPoint(globalPoint:Point):int + { + var localPoint:Point = _sut.globalToLocal(globalPoint); + return _sut.getHeaderIndexAt(localPoint.x, localPoint.y); + } + + private function getColumnIndexAtGlobalPoint(globalPoint:Point):int + { + var localPoint:Point = _dataGrid.grid.globalToLocal(globalPoint); + return _dataGrid.grid.getColumnIndexAt(localPoint.x, localPoint.y); + } + + private function getHeaderShouldContainPointAssumption(point:Point):Boolean + { + return rectangleContainsPoint(entireHeaderRectangle, point); + } + + private function getFixedHeaderViewContainsPointAssumption(point:Point):Boolean + { + return rectangleContainsPoint(fixedHeaderViewRectangle, point); + } + + private function getMainHeaderViewContainsPointAssumption(visibleHeaderViewRectangle:Rectangle, point:Point):Boolean + { + return rectangleContainsPoint(visibleHeaderViewRectangle, point); + } + + private function getHeaderIndexAssumption(point:Point, visibleColumnHeaderRectangles:Array):int + { + return getIndexOfRectangleWhichContainsPoint(point, visibleColumnHeaderRectangles); + } + + private function getColumnIndexAssumption(visibleColumnRectangles:Array, point:Point):int + { + return getIndexOfRectangleWhichContainsPoint(point, visibleColumnRectangles); + } + + private function getIndexOfRectangleWhichContainsPoint(point:Point, rectangles:Array):int + { + for (var i:int = 0; i < rectangles.length; i++) + { + if(rectangleContainsPoint(rectangles[i], point)) + return i; + } + + return -1; + } + + private function rectangleContainsPoint(rectangle:Rectangle, point:Point):Boolean + { + return rectangle.containsPoint(point); + } + + private function getAdjacentPoint(point:Point, direction:Matrix):Point + { + return direction.transformPoint(point); + } + + private function generateKeyPoints(grid:DataGrid):Array + { + var keyPoints:Array = []; + + keyPoints["a"] = new Point(0, 0); + keyPoints["b0"] = new Point(getX(_dimensions), getY(_dimensions)); + generateColumnIntermediates(keyPoints, _dimensions, "b0"); + keyPoints["c0"] = new Point(getX(_dimensions) + getHeaderPaddingLeft(_dimensions), getY(_dimensions)); + generateColumnIntermediates(keyPoints, _dimensions, "c0"); + keyPoints["d"] = new Point(getX(_dimensions) + getWidth(_dimensions), getY(_dimensions)); + keyPoints["e"] = new Point(Point(keyPoints["c0"]).x, getY(_dimensions) + getHeaderPaddingTop(_dimensions)); + keyPoints["f"] = new Point(Point(keyPoints["c0"]).x, getY(_dimensions) + getActualHeaderHeight(grid) - getHeaderPaddingBottom(_dimensions)); + keyPoints["g0"] = new Point(getX(_dimensions), getY(_dimensions) + getActualHeaderHeight(grid)); + generateColumnIntermediates(keyPoints, _dimensions, "g0"); + keyPoints["i"] = new Point(getX(_dimensions) + getWidth(_dimensions), Point(keyPoints["g0"]).y); + return keyPoints; + } + + private function generateColumnIntermediates(keyPoints:Array, dimensions:Array, initialPointName:String):void + { + const initialPoint:Point = keyPoints[initialPointName]; + const y:Number = initialPoint.y; + var currentX:Number = initialPoint.x; + const initialPointFirstCharacter:String = initialPointName.charAt(0); + for (var i:int = 0; i < getColumnWidths(dimensions).length; i++) + { + currentX += getColumnWidth(dimensions, i); + keyPoints[initialPointFirstCharacter + (i+1)] = new Point(currentX, y); + } + } + + private function generateKeyRectangles():Array + { + var keyRectangles:Array = []; + + keyRectangles[ENTIRE_HEADER_RECTANGLE] = generateVisibleHeaderRectangle(); + keyRectangles[FIXED_HEADER_VIEW_RECTANGLE] = generateFixedHeaderViewRectangle(); + + return keyRectangles; + } + + private function generateFixedHeaderViewRectangle():Rectangle + { + //this is the GridColumnHeaderGroup.centerGridColumnHeaderView, which is holds the non-fixed columns; padding excluded + const topLeftCorner:Point = _keyPoints["e"]; + return new Rectangle(topLeftCorner.x, topLeftCorner.y, 0, 0); + } + + private function generateVisibleHeaderRectangle():Rectangle + { + const topLeftCorner:Point = _keyPoints["b0"]; + const bottomRightCorner:Point = _keyPoints["i"]; + return new Rectangle(topLeftCorner.x, topLeftCorner.y, bottomRightCorner.x - topLeftCorner.x, bottomRightCorner.y - topLeftCorner.y); + } + + + private function getActualHeaderHeight(grid:DataGrid):Number + { + //Note that we're assuming the grid is on stage and validated by this point! + return grid.columnHeaderGroup.height; + } + + private function getCurrentHScrollPosition():Number + { + return _dataGrid.grid.horizontalScrollPosition; + } + + + private function getVisibleHeaderViewRectangle(hScrollPosition:Number = 0):Rectangle + { + //this is the GridColumnHeaderGroup.centerGridColumnHeaderView, which holds the non-fixed columns; padding excluded + const topLeftCorner:Point = _keyPoints["e"]; + return new Rectangle(topLeftCorner.x, topLeftCorner.y, + getHeaderWidthFromKeyPoints(_keyPoints) - getHeaderPaddingLeft(_dimensions), + getHeaderHeightFromKeyPoints(_keyPoints) - getHeaderPaddingTop(_dimensions) - getHeaderPaddingBottom(_dimensions)); + } + + private function getVisibleColumnHeaderRectangles(hScrollPosition:Number = 0):Array + { + var headerRectangles:Array = []; + + const headerPaddingTop:Number = getHeaderPaddingTop(_dimensions); + const headerPaddingBottom:Number = getHeaderPaddingBottom(_dimensions); + const headerHeight:Number = getHeaderHeightFromKeyPoints(_keyPoints) - headerPaddingTop - headerPaddingBottom; + const numColumns:uint = getColumnWidths(_dimensions).length; + const headerPaddingLeft:Number = getHeaderPaddingLeft(_dimensions); + const headerWidth:Number = getWidth(_dimensions) - headerPaddingLeft; + const e:Point = _keyPoints["e"]; + const visibleRectangle:Rectangle = new Rectangle(e.x, e.y, headerWidth, 100); + var totalColumnWidths:Number = getTotalColumnWidths(_dimensions); + var columnHeaderY:Number = NaN; + + //create the header rectangles from the first visible point on the left until the end + for (var i:int = 0; i < numColumns; i++) + { + var topLeft:Point = _keyPoints["c" + i]; + var topRight:Point = _keyPoints["c" + (i+1)]; + var topLeftX:Number = topLeft.x - hScrollPosition; + var topRightX:Number = topRight.x - hScrollPosition; + + if(isNaN(columnHeaderY)) + columnHeaderY = topLeft.y + headerPaddingTop; + + var endsBeforeVisibleRectangle:Boolean = topRightX < visibleRectangle.x; + var startsAfterVisibleRectangle:Boolean = topLeftX >= visibleRectangle.x + visibleRectangle.width; + + if(!(endsBeforeVisibleRectangle || startsAfterVisibleRectangle)) + { + const startingX:Number = Math.max(topLeftX, visibleRectangle.x); + const rightEdge:Number = Math.min(topRightX, visibleRectangle.x + visibleRectangle.width); + const width:Number = rightEdge - startingX; + headerRectangles.push(new Rectangle(startingX, columnHeaderY, width, headerHeight)); + } + } + + assertThat("no example has 0 columns, so we expect this Array to have at least one item.", headerRectangles.length > 0); + + //correct last header rectangle to extend to grid boundaries if the total width of all the columns is smaller + //than the grid's width. It is one of the issues which prompted this unit test in the first place. + if(totalColumnWidths <= headerWidth) + { + var lastHeaderRectangle:Rectangle = headerRectangles[headerRectangles.length - 1]; + lastHeaderRectangle.width = Point(_keyPoints["d"]).x - lastHeaderRectangle.x; + } + + return headerRectangles; + } + + + //Note that the height and y of the rectangles needs to be all-encompassing until FLEX-35280 is fixed + private function getAllColumnRectangles(hScrollPosition:Number = 0):Array + { + var columnRectangles:Array = []; + const numColumns:uint = getColumnWidths(_dimensions).length; + + for (var i:int = 0; i < numColumns; i++) + { + var topLeft:Point = _keyPoints["g" + i]; + var topRight:Point = _keyPoints["g" + (i+1)]; + + columnRectangles.push(new Rectangle(topLeft.x, -10000, topRight.x - topLeft.x, Number.MAX_VALUE)); + } + + return columnRectangles; + } + + /* key rectangles getters */ + + private function get entireHeaderRectangle():Rectangle //includes padding + { + return _keyRectangles[ENTIRE_HEADER_RECTANGLE] as Rectangle; + } + + private function get fixedHeaderViewRectangle():Rectangle + { + return _keyRectangles[FIXED_HEADER_VIEW_RECTANGLE] as Rectangle; + } + + /* key points getters */ + + private function getColumnWidthFromKeyPoints(keyPoints:Array, columnIndex:int):Number + { + //we're assuming columnIndex has a valid value + return Point(keyPoints["c" + (columnIndex + 1)]).x - Point(keyPoints["c" + columnIndex]).x; + } + + private function getHeaderHeightFromKeyPoints(keyPoints:Array):Number + { + return Point(keyPoints["i"]).y - Point(keyPoints["d"]).y; + } + + private function getHeaderWidthFromKeyPoints(keyPoints:Array):Number + { + return Point(keyPoints["d"]).x - Point(keyPoints["b0"]).x; + } + + /* dimensions getters */ + + private function getX(dimensions:Array):Number + { + return dimensions[0]; + } + + private function getY(dimensions:Array):Number + { + return dimensions[1]; + } + + private function getWidth(dimensions:Array):Number + { + return dimensions[2]; + } + + private function getHeaderPaddingLeft(dimensions:Array):Number + { + return dimensions[3]; + } + + private function getHeaderPaddingTop(dimensions:Array):Number + { + return dimensions[4]; + } + + private function getHeaderPaddingBottom(dimensions:Array):Number + { + return dimensions[5]; + } + + private function getColumnWidths(dimensions:Array):Array + { + return dimensions[6]; + } + + private function getColumnWidth(dimensions:Array, columnIndex:int):Number + { + return getColumnWidths(dimensions)[columnIndex]; + } + + private function getTotalColumnWidths(dimensions:Array):Number + { + var sum:Number = 0; + getColumnWidths(dimensions).forEach(function (item:*, index:int, arr:Array):void {sum += item;}); + return sum; + } + + + private function onEnterFrame(event:Event):void + { + if(!--_noEnterFramesRemaining) + { + UIImpersonator.testDisplay.removeEventListener(Event.ENTER_FRAME, onEnterFrame); + _finishNotifier.dispatchEvent(new Event(Event.COMPLETE)); + } + } + + private function get _sut():GridColumnHeaderGroup + { + return _dataGrid.columnHeaderGroup; + } + } +} \ No newline at end of file
diff --git a/frameworks/projects/spark_dmv/src/spark/core/Version.as b/frameworks/projects/spark_dmv/src/spark/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/spark_dmv/src/spark/core/Version.as +++ b/frameworks/projects/spark_dmv/src/spark/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/tool/src/mx/core/Version.as b/frameworks/projects/tool/src/mx/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/tool/src/mx/core/Version.as +++ b/frameworks/projects/tool/src/mx/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/frameworks/projects/tool_air/src/mx/core/Version.as b/frameworks/projects/tool_air/src/mx/core/Version.as index 3077bda..9cc2191 100644 --- a/frameworks/projects/tool_air/src/mx/core/Version.as +++ b/frameworks/projects/tool_air/src/mx/core/Version.as
@@ -23,4 +23,4 @@ * @private * Version string for this class. */ -mx_internal static const VERSION:String = "4.16.0.0"; +mx_internal static const VERSION:String = "4.16.1.0";
diff --git a/installer.xml b/installer.xml index 5996861..ef08ef2 100644 --- a/installer.xml +++ b/installer.xml
@@ -351,7 +351,7 @@ <antcall target="air-get" /> <antcall target="air-setup-win" /> - <antcall target="air-setup-mac" /> + <antcall target="air-setup-mac-init" /> </target> @@ -377,7 +377,7 @@ <param name="md5" value="${air.sdk.url.md5}" /> </antcall> </target> - + <target name="air-setup-win" if="isWindows"> <unzip src="${download.dir}/${air.sdk.url.file}" dest="${download.dir}/airsdk" /> <echo>${INFO_FINISHED_UNZIPPING} ${download.dir}/${air.sdk.url.file}</echo> @@ -419,9 +419,8 @@ <echo message="Should unzip: ${shouldUnzip}"/> </target> - <target name="unzipAIRSDK" if="${shouldUnzip}"> + <target name="unzipAIRSDK" if="${shouldUnzip}"> <echo message="Unzipping"/> - <!--The tbz2 contains symlinks which Ant does not preserve <untar compression="bzip2" src="${download.dir}/${air.sdk.url.file}" dest="${download.dir}/airsdk" />--> @@ -441,6 +440,7 @@ <target name="mountAIRSDK" unless="${shouldUnzip}"> <echo message="Mounting dmg"/> + <echo message="IS WINDOWS: ${isWindows}, IS MAC: ${isMac}" /> <exec executable="/usr/bin/hdiutil" os="Mac OS X" failonerror="true"> <arg value="attach"/> <arg value="-nobrowse"/> @@ -448,7 +448,7 @@ </exec> </target> - <target name="copyFromMount" unless="${shouldUnzip}"> + <target name="copyFromMount" unless="${shouldUnzip}"> <echo message="Copying AIR SDK from mounted volume"/> <exec executable="rsync" dir="${FLEX_HOME}"> <arg value="--archive" /> @@ -459,7 +459,7 @@ </exec> </target> - <target name="unmountAIRSDK" unless="${shouldUnzip}"> + <target name="unmountAIRSDK" unless="${shouldUnzip}"> <echo message="Unmounting AIR SDK"/> <exec executable="/usr/bin/hdiutil" os="Mac OS X" failonerror="false"> <arg value="unmount"/> @@ -467,7 +467,11 @@ </exec> </target> - <target name="air-setup-mac" depends="unzipOrMountDMG,unzipAIRSDK,mountAIRSDK,copyFromMount,unmountAIRSDK" unless="isWindows"> + <target name="air-setup-mac-init" unless="isWindows"> + <antcall target="air-setup-mac" /> + </target> + + <target name="air-setup-mac" depends="unzipOrMountDMG,unzipAIRSDK,mountAIRSDK,copyFromMount,unmountAIRSDK"> <antcall target="mac-copy-file"> <param name="srcdir" value="." /> <param name="filename" value="AIR SDK license.pdf"/>
diff --git a/modules/asc/src/java/macromedia/asc/embedding/LintEvaluator.java b/modules/asc/src/java/macromedia/asc/embedding/LintEvaluator.java index de2ea96..359af64 100644 --- a/modules/asc/src/java/macromedia/asc/embedding/LintEvaluator.java +++ b/modules/asc/src/java/macromedia/asc/embedding/LintEvaluator.java
@@ -749,8 +749,14 @@ boolean is_unbound_ref = is_unbound_dotref || is_unbound_lexref || is_unbound_globalref; - if (slot != null ) + if (slot != null && !(node.expr instanceof QualifiedIdentifierNode)) + { + //if it's a qualified identifier node, then it's a member/static + //variable on a class that is being initialized, like this: + //public var memberVar:String = "hi"; + //this case should not have a warning! checkDeprecatedSlot(cx, node.expr, node.ref, slot); + } // special case to avoid warning on access to a Class's prototype property. This // property can't be expressed in global.as because you can't both declare a class
diff --git a/modules/compiler/src/java/flex2/compiler/common/MxmlConfiguration.java b/modules/compiler/src/java/flex2/compiler/common/MxmlConfiguration.java index 08a9c0c..1614611 100644 --- a/modules/compiler/src/java/flex2/compiler/common/MxmlConfiguration.java +++ b/modules/compiler/src/java/flex2/compiler/common/MxmlConfiguration.java
@@ -46,6 +46,8 @@ // // 'compiler.mxml.compatibility-version' option // + public static final int VERSION_4_16_1 = 0x04100001; + public static final int VERSION_4_16 = 0x04100000; public static final int VERSION_4_15 = 0x040f0000; public static final int VERSION_4_14_1 = 0x040e0001; public static final int VERSION_4_14 = 0x040e0000; @@ -63,10 +65,10 @@ public static final int VERSION_3_0 = 0x03000000; public static final int VERSION_2_0_1 = 0x02000001; public static final int VERSION_2_0 = 0x02000000; - public static final int CURRENT_VERSION = VERSION_4_15; + public static final int CURRENT_VERSION = VERSION_4_16_1; public static final int EARLIEST_MAJOR_VERSION = 3; public static final int LATEST_MAJOR_VERSION = 4; - public static final int LATEST_MINOR_VERSION = 15; + public static final int LATEST_MINOR_VERSION = 16; private int major = LATEST_MAJOR_VERSION; private int minor = LATEST_MINOR_VERSION;
diff --git a/modules/compiler/src/java/flex2/tools/VersionInfo.java b/modules/compiler/src/java/flex2/tools/VersionInfo.java index 6e740cc..4ded09c 100644 --- a/modules/compiler/src/java/flex2/tools/VersionInfo.java +++ b/modules/compiler/src/java/flex2/tools/VersionInfo.java
@@ -33,7 +33,7 @@ { public static String FLEX_MAJOR_VERSION = "4"; public static String FLEX_MINOR_VERSION = "16"; - public static String FLEX_NANO_VERSION = "0"; + public static String FLEX_NANO_VERSION = "1"; /** * Lib version is the "version" of the SWC format. Major number changes represent big (although not
diff --git a/releasecandidate.xml b/releasecandidate.xml index 7597846..c2d43f8 100644 --- a/releasecandidate.xml +++ b/releasecandidate.xml
@@ -49,9 +49,10 @@ </condition> <property name="rat.report" value="${basedir}/rat-report.txt"/> - <property name="apache.rat.jar" value="apache-rat-0.8.jar" /> - <property name="apache.rat.tasks.jar" value="apache-rat-tasks-0.8.jar" /> - <property name="apache.rat.url" value="http://people.apache.org/~aharui/rat" /> + <property name="apache.rat.jar" value="apache-rat-0.11.jar" /> + <property name="apache.rat.tasks.jar" value="apache-rat-tasks-0.11.jar" /> + <property name="apache.rat.url" value="http://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat/0.11" /> + <property name="apache.rat.tasks.url" value="http://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat-tasks/0.11"/> <property file="${basedir}/local.properties" /> <property file="${basedir}/build.properties" /> @@ -192,7 +193,7 @@ <get src="${apache.rat.url}/${apache.rat.jar}" dest="${env.ANT_HOME}/lib/${apache.rat.jar}" /> </target> <target name="install-rat.tasks.jar" unless="apache.rat.tasks.found"> - <get src="${apache.rat.url}/${apache.rat.tasks.jar}" dest="${env.ANT_HOME}/lib/${apache.rat.tasks.jar}" /> + <get src="${apache.rat.tasks.url}/${apache.rat.tasks.jar}" dest="${env.ANT_HOME}/lib/${apache.rat.tasks.jar}" /> </target> <target name="rat-taskdef" description="Rat taskdef">