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">