diff --git a/.gitignore b/.gitignore
index 6aec5f76..50366b3b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,17 @@
-Thumbs.db
.*
-bin-*
bin
+bin-*
+doc*
+report*
html-template
-*.swf
-docs
build.properties
reports
-tests
+flex-config.xml
+FlexUnit*
+Thumbs.db
+*.iml
+*.ipr
+*.iws
+*.swf
+target
+
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 00000000..dea53d75
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,21 @@
+# MIT Open Source License
+
+Copyright (c) 2009-2010 the original author or authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
index 113c3513..5f1c6e00 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,3 @@
-# Reflex
+# Reflex Framework
-Reflex is a light weight component framework being built for the Flash Platform. You can find more information at [reflex.io](http://reflex.io).
+The Reflex Framework is an ActionScript 3 component framework for the Flash Platform. You can find more information at [reflexplatform.com](http://reflexplatform.com).
diff --git a/assets/skin/cursors.fla b/assets/skin/cursors.fla
deleted file mode 100644
index 7be29c53..00000000
Binary files a/assets/skin/cursors.fla and /dev/null differ
diff --git a/assets/skin/skins-cs5.fla b/assets/skin/skins-cs5.fla
deleted file mode 100644
index f5ff0208..00000000
Binary files a/assets/skin/skins-cs5.fla and /dev/null differ
diff --git a/assets/skin/skins.fla b/assets/skin/skins.fla
deleted file mode 100644
index c2f83311..00000000
Binary files a/assets/skin/skins.fla and /dev/null differ
diff --git a/build.xml b/build.xml
index 0f91e145..aa065cf4 100644
--- a/build.xml
+++ b/build.xml
@@ -1,5 +1,5 @@
- An The If a filter is unsupported, Flex throws an error when accessing
+ * this property.
+ * You must call Note: The Flex implementations of ICollectionView retrieve all
+ * items from a remote location before executing the filter function.
+ * If you use paging, apply the filter to the remote collection before
+ * you retrieve the data. Note: The Flex implementations of ICollectionView retrieve all
+ * items from a remote location before executing a sort.
+ * If you use paging with a sorted list, apply the sort to the remote
+ * collection before you retrieve the data. Returns An The Note: unlike If any item is not local and an asynchronous operation must be
+ * performed, an See the ItemPendingError documentation as well as
+ * the collections documentation for more information
+ * on using the The compare function must have the following signature: This function must return the following value:
+ * ICollectionView. Bookmarks are used to return a cursor to
+ * an absolute position within the ICollectionView.
+ *
+ * @see mx.collections.IViewCursor#bookmark
+ * @see mx.collections.IViewCursor#seek()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class CursorBookmark
+{
+ include "../core/Version.as";
+
+ private static var _first:CursorBookmark;
+ private static var _last:CursorBookmark;
+ private static var _current:CursorBookmark;
+
+ /**
+ * A bookmark for the first item in an ICollectionView.
+ *
+ * @return The bookmark to the first item.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function get FIRST():CursorBookmark
+ {
+ if (!_first)
+ _first = new CursorBookmark("${F}");
+ return _first;
+ }
+
+ /**
+ * A bookmark for the last item in an ICollectionView.
+ * If the view has no items, the cursor is at this bookmark.
+ *
+ * @return The bookmark to the last item.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function get LAST():CursorBookmark
+ {
+ if (!_last)
+ _last = new CursorBookmark("${L}");
+ return _last;
+ }
+
+ /**
+ * A bookmark representing the current item for the IViewCursor in
+ * an ICollectionView.
+ *
+ * @return The bookmark to the current item.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function get CURRENT():CursorBookmark
+ {
+ if (!_current)
+ _current = new CursorBookmark("${C}");
+ return _current;
+ }
+
+ /**
+ * Creates a new instance of a bookmark with the specified value.
+ *
+ * @param value The value of this bookmark.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function CursorBookmark(value:Object)
+ {
+ super();
+ _value = value;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // value
+ //----------------------------------
+
+ private var _value:Object;
+
+ /**
+ * The underlying marker representation of the bookmark.
+ * This value is generally understood only by the IViewCursor
+ * or ICollectionView implementation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get value():Object
+ {
+ return _value;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Gets the approximate index of the item represented by this bookmark
+ * in its view. If the item has been paged out, this method could throw an
+ * ItemPendingError.
+ *
+ * @return The index of the item. If the item is not in the current view, this method returns
+ * -1. This method also returns -1 if index-based location is not possible.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function getViewIndex():int
+ {
+ return -1;
+ }
+}
+
+}
diff --git a/src/mx/collections/ICollectionView.as b/src/mx/collections/ICollectionView.as
new file mode 100644
index 00000000..d79ef18f
--- /dev/null
+++ b/src/mx/collections/ICollectionView.as
@@ -0,0 +1,286 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.collections
+{
+
+import flash.events.IEventDispatcher;
+import mx.events.CollectionEvent;
+
+/**
+ * Dispatched when the ICollectionView has been updated in some way.
+ *
+ * @eventType mx.events.CollectionEvent.COLLECTION_CHANGE
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+[Event(name="collectionChange", type="mx.events.CollectionEvent")]
+
+/**
+ * An ICollectionView is a view onto a collection of data.
+ * The view can be modified to show the data sorted according to various
+ * criteria or reduced by filters without modifying the underlying data.
+ * An IViewCursor provides to access items within a
+ * collection. You can modify the collection by using the IViewCursor
+ * interface insert() and remove() methods.
+ *
+ * ICollectionView may be a view onto data that has been
+ * retrieved from a remote location.
+ * When Implementing this interface for data
+ * that may be remote it is important to handle the case where data
+ * may not yet be available, which is indicated by the
+ * ItemPendingError.IList interface is an alternative to the
+ * ICollectionView interface.f(item:Object):Boolean
+ *
+ * where the return value is true if the specified item
+ * should remain in the view.
+ *
+ * refresh() after setting the
+ * filterFunction property for the view to update.refresh() method
+ * after setting this property.
+ * If sort is unsupported an error will be thrown when accessing
+ * this property.
+ *
+ * IViewCursor.findxxx methods,
+ * this search is succesful only if it finds an item that exactly
+ * matches the parameter.
+ * If the view has a filter applied to it this method may return
+ * false even if the underlying collection
+ * does contain the item.
+ *
+ * @param item The object to look for.
+ *
+ * @return true if the ICollectionView, after applying any filter,
+ * contains the item; false otherwise.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function contains(item:Object):Boolean;
+
+ /**
+ * Prevents changes to the collection itself and items within the
+ * collection from being dispatched by the view.
+ * Also prevents the view from updating the positions of items
+ * if the positions change in the collection.
+ * The changes will be queued and dispatched appropriately
+ * after enableAutoUpdate is called.
+ * If more events than updates to a single item occur,
+ * the view may end up resetting.
+ * The disableAutoUpdate method acts cumulatively;
+ * the same number of calls to enableAutoUpdate
+ * are required for the view to dispatch events and refresh.
+ * Note that disableAutoUpdate only affects the
+ * individual view; edits may be detected on an individual
+ * basis by other views.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function disableAutoUpdate():void;
+
+ /**
+ * Enables auto-updating.
+ * See disableAutoUpdate for more information.
+ *
+ * @see #disableAutoUpdate()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function enableAutoUpdate():void;
+
+ /**
+ * Notifies the view that an item has been updated.
+ * This method is useful if the contents of the view do not implement
+ * IPropertyChangeNotifier.
+ * If the call to this method includes a property parameter,
+ * the view may be able to optimize its notification mechanism.
+ * Otherwise it may choose to simply refresh the whole view.
+ *
+ * @param item The item within the view that was updated.
+ *
+ * @param property The name of the property that was updated.
+ *
+ * @param oldValue The old value of that property. (If property
+ * was null, this can be the old value of the item.).
+ *
+ * @param newValue The new value of that property. (If property
+ * was null, there's no need to specify this as the item is assumed
+ * to be the new value.)
+ *
+ * @see mx.events.CollectionEvent
+ * @see mx.core.IPropertyChangeNotifier
+ * @see mx.events.PropertyChangeEvent
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function itemUpdated(item:Object, property:Object = null,
+ oldValue:Object = null, newValue:Object = null):void;
+
+ /**
+ * Applies the sort and filter to the view.
+ * The ICollectionView does not detect changes to a sort or
+ * filter automatically, so you must call the refresh()
+ * method to update the view after setting the sort
+ * or filterFunction property.
+ * If your ICollectionView implementation also implements
+ * the IMXMLObject interface, you should to call the
+ * refresh() method from your initialized()
+ * method.
+ *
+ * true if the refresh was successful
+ * and false if the sort is not yet complete
+ * (e.g., items are still pending).
+ * A client of the view should wait for a CollectionEvent event
+ * with the CollectionEventKind.REFRESH kind
+ * property to ensure that the refresh() operation is
+ * complete.true if the refresh() was complete,
+ * false if the refresh() is incomplete.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function refresh():Boolean;
+}
+
+}
diff --git a/src/mx/collections/IList.as b/src/mx/collections/IList.as
new file mode 100644
index 00000000..e054d4fe
--- /dev/null
+++ b/src/mx/collections/IList.as
@@ -0,0 +1,263 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.collections
+{
+
+import flash.events.IEventDispatcher;
+import mx.events.CollectionEvent;
+
+/**
+ * Dispatched when the IList has been updated in some way.
+ *
+ * @eventType mx.events.CollectionEvent.COLLECTION_CHANGE
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+[Event(name="collectionChange", type="mx.events.CollectionEvent")]
+
+/**
+ * A collection of items organized in an ordinal fashion.
+ * Provides access and manipulation methods based on index.
+ *
+ * IList may be a view onto data
+ * that has been retrieved from a remote location.
+ * When writing for a collection that may be remote,
+ * it is important to handle the case where data
+ * may not yet be available, which is indicated
+ * by the ItemPendingError.ICollectionView is an alternative
+ * to the IList.addItemAt(item, length).
+ *
+ * @param item The item to add.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function addItem(item:Object):void;
+
+ /**
+ * Adds the item at the specified index.
+ * The index of any item greater than the index of the added item is increased by one.
+ * If the the specified index is less than zero or greater than the length
+ * of the list, a RangeError is thrown.
+ *
+ * @param item The item to place at the index.
+ *
+ * @param index The index at which to place the item.
+ *
+ * @throws RangeError if index is less than 0 or greater than the length of the list.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function addItemAt(item:Object, index:int):void;
+
+ /**
+ * Gets the item at the specified index.
+ *
+ * @param index The index in the list from which to retrieve the item.
+ *
+ * @param prefetch An int indicating both the direction
+ * and number of items to fetch during the request if the item is
+ * not local.
+ *
+ * @return The item at that index, or null if there is none.
+ *
+ * @throws mx.collections.errors.ItemPendingError if the data for that index needs to be
+ * loaded from a remote location.
+ *
+ * @throws RangeError if index < 0
+ * or index >= length.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getItemAt(index:int, prefetch:int = 0):Object;
+
+ /**
+ * Returns the index of the item if it is in the list such that
+ * getItemAt(index) == item.
+ *
+ * IViewCursor.findxxx() methods,
+ * The getItemIndex() method cannot take a parameter with
+ * only a subset of the fields in the item being serched for;
+ * this method always searches for an item that exactly matches
+ * the input parameter.IEventDispatcher and dispatches a
+ * PropertyChangeEvent.
+ * If a property is specified the view may be able to optimize its
+ * notification mechanism.
+ * Otherwise it may choose to simply refresh the whole view.
+ *
+ * @param item The item within the view that was updated.
+ *
+ * @param property The name of the property that was updated.
+ *
+ * @param oldValue The old value of that property. (If property was null,
+ * this can be the old value of the item.)
+ *
+ * @param newValue The new value of that property. (If property was null,
+ * there's no need to specify this as the item is assumed to be
+ * the new value.)
+ *
+ * @see mx.events.CollectionEvent
+ * @see mx.events.PropertyChangeEvent
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function itemUpdated(item:Object, property:Object = null,
+ oldValue:Object = null,
+ newValue:Object = null):void;
+
+ /**
+ * Removes all items from the list.
+ *
+ * ItemPendingError will be thrown.ItemPendingError.null if none.
+ *
+ * @throws RangeError if index is less than 0 or greater than length.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function setItemAt(item:Object, index:int):Object;
+
+ /**
+ * Returns an Array that is populated in the same order as the IList
+ * implementation.
+ * This method can throw an ItemPendingError.
+ *
+ * @return The array.
+ *
+ * @throws mx.collections.errors.ItemPendingError If the data is not yet completely loaded
+ * from a remote location.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function toArray():Array;
+}
+
+}
diff --git a/src/mx/collections/ISort.as b/src/mx/collections/ISort.as
new file mode 100644
index 00000000..709c26d7
--- /dev/null
+++ b/src/mx/collections/ISort.as
@@ -0,0 +1,325 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2010 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.collections
+{
+
+ /**
+ * The ISort interface defines the interface for classes that
+ * provide the sorting information required to sort the
+ * data of a collection view.
+ *
+ * @see mx.collections.ICollectionView
+ * @see mx.collections.ISortField
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 4.5
+ */
+public interface ISort
+{
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * The method used to compare items when sorting.
+ * If you specify this property, Flex ignores any
+ * compareFunction properties that you specify in the
+ * ISortField objects that you use in this class.
+ *
+ *
+ *
+ *
+ *
+ * function [name](a:Object, b:Object, fields:Array = null):int
+ *
+ *
+ *
Object a should appear before the
+ * Object b in the sorted sequenceObject a equals the
+ * Object bObject a should appear after the
+ * Object b in the sorted sequence
To return to the internal comparision function, set this value to
+ * null.
+ * The fields array specifies the object fields
+ * to compare.
+ * Typically the algorithm will compare properties until the field list is
+ * exhausted or a non-zero value can be returned.
+ * For example:
+ * function myCompare(a:Object, b:Object, fields:Array = null):int
+ * {
+ * var result:int = 0;
+ * var i:int = 0;
+ * var propList:Array = fields ? fields : internalPropList;
+ * var len:int = propList.length;
+ * var propName:String;
+ * while (result == 0 && (i < len))
+ * {
+ * propName = propList[i];
+ * result = compareValues(a[propName], b[propName]);
+ * i++;
+ * }
+ * return result;
+ * }
+ *
+ * function compareValues(a:Object, b:Object):int
+ * {
+ * if (a == null && b == null)
+ * return 0;
+ *
+ * if (a == null)
+ * return 1;
+ *
+ * if (b == null)
+ * return -1;
+ *
+ * if (a < b)
+ * return -1;
+ *
+ * if (a > b)
+ * return 1;
+ *
+ * return 0;
+ * }
+ *
+ *
+ * The default value is an internal compare function that can perform + * a string, numeric, or date comparison in ascending or descending order. + * Specify your own function only if you need a need a custom + * comparison algorithm. This is normally only the case if a calculated + * field is used in a display.
+ * + *Alternatively you can specify separate compare functions for each
+ * sort field by using the ISortField class
+ * compareFunction property; This way you can use the default
+ * comparison for some fields and a custom comparison for others.
Array of ISortField objects that specifies the fields to compare.
+ * The order of the ISortField objects in the array determines
+ * field priority order when sorting.
+ * The default sort comparator checks the sort fields in array
+ * order until it determinines a sort order for the two
+ * fields being compared.
+ *
+ * @default null
+ *
+ * @see ISortField
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 4.5
+ */
+ function get fields():Array;
+ function set fields(value:Array):void;
+
+ /**
+ * Indicates if the sort should be unique.
+ * Unique sorts fail if any value or combined value specified by the
+ * fields listed in the fields property result in an indeterminate or
+ * non-unique sort order; that is, if two or more items have identical
+ * sort field values. An error is thrown if the sort is not unique.
+ * The sorting logic uses this unique property value only if sort
+ * field(s) are specified explicitly. If no sort fields are specified
+ * explicitly, no error is thrown even when there are identical value
+ * elements.
+ *
+ * @default false
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 4.5
+ */
+ function get unique():Boolean;
+ function set unique(value:Boolean):void;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Finds the specified object within the specified array (or the insertion
+ * point if asked for), returning the index if found or -1 if not.
+ * The ListCollectionView class findxxx()
+ * methods use this method to find the requested item; as a general rule,
+ * it is easier to use these functions, and not findItem()
+ * to find data in ListCollectionView-based objects.
+ * You call the findItem() method directly when writing a
+ * class that supports sorting, such as a new ICollectionView
+ * implementation.
+ * The input items array need to be sorted before calling this function.
+ * Otherwise this function will not be able to find the specified value
+ * properly.
+ *
+ * @param items the Array within which to search.
+ * @param values Object containing the properties to look for (or
+ * the object to search for, itself).
+ * The object must consist of field name/value pairs, where
+ * the field names are names of fields specified by the
+ * fields property, in the same order they
+ * are used in that property.
+ * You do not have to specify all of the fields from the
+ * fields property, but you
+ * cannot skip any in the order.
+ * Therefore, if the fields
+ * properity lists three fields, you can specify its first
+ * and second fields in this parameter, but you cannot
+ * specify only the first and third fields.
+ * @param mode String containing the type of find to perform.
+ * Valid values are:
+ * | ANY_INDEX_MODE | + *Return any position that + * is valid for the values. | + *
|---|---|
| FIRST_INDEX_MODE | + *Return the position + * where the first occurrance of the values is found. | + *
| LAST_INDEX_MODE | + *Return the position where the + * last ocurrance of the specified values is found. + * | + *
values parameter,
+ * and this parameter is true the
+ * findItem()
+ * method returns the insertion point for the values,
+ * that is the point in the sorted order where you
+ * should insert the item.
+ * @param compareFunction a comparator function to use to find the item.
+ * If you do not specify this parameter or , or if you
+ * provide a null value,
+ * findItem() function uses the
+ * compare function determined by the ISort
+ * instance's compareFunction property,
+ * passing in the array of fields determined
+ * by the values object and the current
+ * SortFields.
+ *
+ * If you provide a non-null value, findItem()
+ * function uses it as the compare function.
+ *
+ * The signature of the function passed as
+ * compareFunction must be as follows:
+ * function myCompareFunction(a:Object, b:Object):int.
+ * Note that there is no third argument unlike the
+ * compare function for ISort.compareFunction()
+ * property.
+ * @return int The index in the array of the found item.
+ * If the returnInsertionIndex parameter is
+ * false and the item is not found, returns -1.
+ * If the returnInsertionIndex parameter is
+ * true and the item is not found, returns
+ * the index of the point in the sorted array where the
+ * values would be inserted.
+ *
+ * @throws SortError If there are any parameter errors,
+ * the find critieria is not compatible with the sort
+ * or the comparator function for the sort can not be determined.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 4.5
+ */
+ function findItem(
+ items:Array,
+ values:Object,
+ mode:String,
+ returnInsertionIndex:Boolean = false,
+ compareFunction:Function = null):int;
+
+ /**
+ * Return whether the specified property is used to control the sort.
+ * The function cannot determine a definitive answer if the sort uses a
+ * custom comparator; it always returns true in this case.
+ *
+ * @param property The name of the field that to test.
+ * @return Whether the property value might affect the sort outcome.
+ * If the sort uses the default compareFunction, returns
+ * true if the
+ * property parameter specifies a sort field.
+ * If the sort or any ISortField uses a custom comparator,
+ * there's no way to know, so return true.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 4.5
+ */
+ function propertyAffectsSort(property:String):Boolean;
+
+ /**
+ * Goes through the fields array and calls
+ * reverse() on each of the ISortField objects in
+ * the array. If the field was descending now it is ascending,
+ * and vice versa.
+ *
+ * Note: an ICollectionView does not automatically
+ * update when the objects in the fields array are modified;
+ * call its refresh() method to update the view.
items parameter.
+ *
+ * Flex ICollectionView implementations call the
+ * sort method automatically and ensure that the sort is
+ * performed on a copy of the underlying data.
createCursor() method) the value of the
+ * current property should be the first
+ * item in the view, unless the view is empty.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public interface IViewCursor extends IEventDispatcher
+{
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // afterLast
+ //----------------------------------
+
+ [Bindable("cursorUpdate")]
+
+ /**
+ * If the cursor is located after the last item in the view,
+ * this property is true .
+ * If the ICollectionView is empty (length == 0),
+ * this property is true.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get afterLast():Boolean;
+
+ //----------------------------------
+ // beforeFirst
+ //----------------------------------
+
+ [Bindable("cursorUpdate")]
+
+ /**
+ * If the cursor is located before the first item in the view,
+ * this property is true.
+ * If the ICollectionView is empty (length == 0),
+ * this property is true.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get beforeFirst():Boolean;
+
+ //----------------------------------
+ // bookmark
+ //----------------------------------
+
+ [Bindable("cursorUpdate")]
+
+ /**
+ * Provides access to a bookmark that corresponds to the item
+ * returned by the current property.
+ * The bookmark can be used to move the cursor
+ * to a previously visited item, or to a position relative to that item.
+ * (See the seek() method for more information.)
+ *
+ * @see #current
+ * @see #seek()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get bookmark():CursorBookmark;
+
+ //----------------------------------
+ // current
+ //----------------------------------
+
+ [Bindable("cursorUpdate")]
+
+ /**
+ * Provides access the object at the location
+ * in the source collection referenced by this cursor.
+ * If the cursor is beyond the ends of the collection
+ * (beforeFirst, afterLast)
+ * this will return null.
+ *
+ * @see #moveNext()
+ * @see #movePrevious()
+ * @see #seek()
+ * @see #beforeFirst
+ * @see #afterLast
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get current():Object;
+
+ //----------------------------------
+ // view
+ //----------------------------------
+
+ /**
+ * A reference to the ICollectionView with which this cursor is associated.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get view():ICollectionView;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Finds an item with the specified properties within the collection
+ * and positions the cursor to that item.
+ * If the item can not be found, the cursor location does not change.
+ *
+ * The findAny() method can only be called on sorted views;
+ * if the view isn't sorted, a CursorError is thrown.
If the associated collection is remote, and not all of the items + * have been cached locally, this method begins an asynchronous fetch + * from the remote collection. If one is already in progress, this method + * waits for it to complete before making another fetch request.
+ * + *If multiple items can match the search criteria then the item found
+ * is non-deterministic.
+ * If it is important to find the first or last occurrence of an item
+ * in a non-unique index, use the findFirst() or
+ * findLast() method.
If the data is not local and an asynchronous operation must be + * performed, an ItemPendingError is thrown.
+ * + * @param values The search criteria. The values in the Object must be configured as name-value pairs, + * as in an associative array (or be the actual object to search for). The values of the names specified must match properties + * specified in the sort. For example, if propertiesx, y, and
+ * z are in the current sort, the values specified should be
+ * {x: x-value, y: y-value, z: z-value}.
+ *
+ * @return When all of the data is local this method returns
+ * true if the item can be found and false
+ * otherwise.
+ *
+ * @see #findFirst()
+ * @see #findLast()
+ * @see mx.collections.errors.ItemPendingError
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function findAny(values:Object):Boolean;
+
+ /**
+ * Finds the first item with the specified properties within the collection
+ * and positions the cursor to that item.
+ * If the item can not be found, no cursor location does not change.
+ *
+ * The findFirst() method can only be called on sorted views;
+ * if the view isn't sorted, a CursorError is thrown.
If the associated collection is remote, and not all of the items + * have been cached locally, this method begins an asynchronous fetch + * from the remote collection. If one is already in progress, this method + * waits for it to complete before making another fetch request.
+ * + *If it is not important to find the first occurrence of an item
+ * in a non-unique index, use findAny(), which may be
+ * a little faster than the findFirst() method.
If the data is not local and an asynchronous operation must be + * performed, an ItemPendingError is thrown.
+ * + * @param values The search criteria. The values in the Object must be configured as name-value pairs, + * as in an associative array (or be the actual object to search for). The values of the names specified must match properties + * specified in the sort. For example, if propertiesx, y, and
+ * z are in the current sort, the values specified should be
+ * {x: x-value, y: y-value, z: z-value}.
+ *
+ * @return When all of the data is local this method returns
+ * true if the item can be found and false
+ * otherwise.
+ *
+ * @see #findAny()
+ * @see #findLast()
+ * @see mx.collections.errors.ItemPendingError
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function findFirst(values:Object):Boolean;
+
+ /**
+ * Finds the last item with the specified properties within the collection
+ * and positions the cursor on that item.
+ * If the item can not be found, the cursor location does not chanage.
+ *
+ * The findLast() method can only be called on sorted views;
+ * if the view isn't sorted, a CursorError is thrown.
If the associated collection is remote, and not all of the items + * have been cached locally, this method begins an asynchronous fetch + * from the remote collection. If one is already in progress, this method + * waits for it to complete before making another fetch request.
+ * + *If it is not important to find the last occurrence of an item
+ * in a non-unique index, use the findAny() method, which
+ * may be a little faster.
If the data is not local and an asynchronous operation must be + * performed, an ItemPendingError is thrown.
+ * + * @param values The search criteria. The values in the Object must be configured as name-value pairs, + * as in an associative array (or be the actual object to search for). The values of the names specified must match properties + * specified in the sort. For example, if propertiesx, y, and
+ * z are in the current sort, the values specified should be
+ * {x: x-value, y: y-value, z: z-value}.
+ *
+ * @return When all of the data is local this method returns
+ * true if the item can be found and false
+ * otherwise.
+ *
+ * @see #findAny()
+ * @see #findFirst()
+ * @see mx.collections.errors.ItemPendingError
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function findLast(values:Object):Boolean;
+
+ /**
+ * Inserts the specified item before the cursor's current position.
+ * If the cursor is afterLast,
+ * the insertion occurs at the end of the view.
+ * If the cursor is beforeFirst on a non-empty view,
+ * an error is thrown.
+ *
+ * @param item The item to insert before the cursor's current position.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function insert(item:Object):void;
+
+ /**
+ * Moves the cursor to the next item within the collection.
+ * On success the current property is updated
+ * to reference the object at this new location.
+ * Returns true if the resulting current
+ * property is valid, or false if not
+ * (the property value is afterLast).
+ *
+ * If the data is not local and an asynchronous operation must be performed, + * an ItemPendingError is thrown. + * See the ItemPendingError documentation and the collections + * documentation for more information on using the ItemPendingError.
+ * + * @returntrue if still in the list,
+ * false if the current value initially was
+ * or now is afterLast.
+ *
+ * @see #current
+ * @see #movePrevious()
+ * @see mx.collections.errors.ItemPendingError
+ *
+ * @example
+ *
+ * var myArrayCollection:ICollectionView = new ArrayCollection([ "Bobby", "Mark", "Trevor", "Jacey", "Tyler" ]);
+ * var cursor:IViewCursor = myArrayCollection.createCursor();
+ * while (!cursor.afterLast)
+ * {
+ * trace(cursor.current);
+ * cursor.moveNext();
+ * }
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function moveNext():Boolean;
+
+ /**
+ * Moves the cursor to the previous item within the collection.
+ * On success the current property is updated
+ * to reference the object at this new location.
+ * Returns true if the resulting current
+ * property is valid, or false if not
+ * (the property value is beforeFirst).
+ *
+ * If the data is not local and an asynchronous operation must be performed, + * an ItemPendingError is thrown. + * See the ItemPendingError documentation and the collections + * documentation for more information on using the ItemPendingError.
+ * + * @returntrue if still in the list,
+ * false if the current value initially was or
+ * now is beforeFirst.
+ *
+ * For example:
+ *
+ * var myArrayCollection:ICollectionView = new ArrayCollection([ "Bobby", "Mark", "Trevor", "Jacey", "Tyler" ]);
+ * var cursor:IViewCursor = myArrayCollection.createCursor();
+ * cursor.seek(CursorBookmark.last);
+ * while (!cursor.beforeFirst)
+ * {
+ * trace(current);
+ * cursor.movePrevious();
+ * }
+ *
+ *
+ * @see #current
+ * @see #moveNext()
+ * @see mx.collections.errors.ItemPendingError
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function movePrevious():Boolean;
+
+ /**
+ * Removes the current item and returns it.
+ * If the cursor location is beforeFirst or
+ * afterLast, throws a CursorError.
+ * If you remove any item other than the last item,
+ * the cursor moves to the next item. If you remove the last item, the
+ * cursor is at the AFTER_LAST bookmark.
+ *
+ * If the item after the removed item is not local and an asynchronous + * operation must be performed, an ItemPendingError is thrown. + * See the ItemPendingError documentation and the collections + * documentation for more information on using the ItemPendingError.
+ * + * @return The item that was removed. + * + * @see mx.collections.errors.ItemPendingError + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + function remove():Object; + + /** + * Moves the cursor to a location at an offset from the specified + * bookmark. + * The offset can be negative, in which case the cursor is positioned + * anoffset number of items prior to the specified bookmark.
+ *
+ * If the associated collection is remote, and not all of the items + * have been cached locally, this method begins an asynchronous fetch + * from the remote collection.
+ * + *If the data is not local and an asynchronous operation + * must be performed, an ItemPendingError is thrown. + * See the ItemPendingError documentation and the collections + * documentation for more information on using the ItemPendingError.
+ * + * @param bookmarkCursorBookmark reference to marker
+ * information that allows repositioning to a specific location.
+ * You can set this parameter to value returned from the
+ * bookmark property, or to one of the following constant
+ * bookmark values:
+ * CursorBookmark.FIRST -
+ * Seek from the start (first element) of the collectionCursorBookmark.CURRENT -
+ * Seek from the current position in the collectionCursorBookmark.LAST -
+ * Seek from the end (last element) of the collectionbeforeFirst or afterLast location.
+ *
+ * @param prefetch Used for remote data. Indicates an intent to iterate
+ * in a specific direction once the seek operation completes.
+ * This reduces the number of required network round trips during a seek.
+ * If the iteration direction is known at the time of the request,
+ * the appropriate amount of data can be returned ahead of the request
+ * to iterate it.
+ *
+ * @see mx.collections.errors.ItemPendingError
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function seek(bookmark:CursorBookmark, offset:int = 0, prefetch:int = 0):void;
+}
+
+}
diff --git a/src/mx/collections/errors/CollectionViewError.as b/src/mx/collections/errors/CollectionViewError.as
new file mode 100644
index 00000000..f8aee23d
--- /dev/null
+++ b/src/mx/collections/errors/CollectionViewError.as
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.collections.errors
+{
+
+/**
+ * The CollectionViewError class represents general errors
+ * within a collection that are not related to specific activities
+ * such as Cursor seeking.
+ * Errors of this class are thrown by the ListCollectionView class.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class CollectionViewError extends Error
+{
+ include "../../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor.
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param message A message providing information about the error cause.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function CollectionViewError(message:String)
+ {
+ super(message);
+ }
+}
+
+}
diff --git a/src/mx/collections/errors/CursorError.as b/src/mx/collections/errors/CursorError.as
new file mode 100644
index 00000000..67305ddc
--- /dev/null
+++ b/src/mx/collections/errors/CursorError.as
@@ -0,0 +1,51 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.collections.errors
+{
+
+/**
+ * This error is thrown by a collection Cursor.
+ * Errors of this class are thrown by classes
+ * that implement the IViewCursor interface.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class CursorError extends Error
+{
+ include "../../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor.
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param message A message providing information about the error cause.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function CursorError(message:String)
+ {
+ super(message);
+ }
+}
+
+}
diff --git a/src/mx/collections/errors/ItemPendingError.as b/src/mx/collections/errors/ItemPendingError.as
new file mode 100644
index 00000000..3e6177d1
--- /dev/null
+++ b/src/mx/collections/errors/ItemPendingError.as
@@ -0,0 +1,125 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.collections.errors
+{
+
+import mx.rpc.IResponder;
+
+/**
+ * This error is thrown when retrieving an item from a collection view
+ * requires an asynchronous call. This error occurs when the backing data
+ * is provided from a remote source and the data is not yet available locally.
+ *
+ * If the receiver of this error needs notification when the requested item
+ * becomes available (that is, when the asynchronous call completes), it must
+ * use the addResponder() method and specify
+ * an object that supports the mx.rpc.IResponder
+ * interface to respond when the item is available.
+ * The mx.collections.ItemResponder class implements the
+ * IResponder interface and supports a data property.
Called by the Flex Framework when a request is made + * for an item that isn't local.
+ * + * @param message A message providing information about the error cause. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function ItemPendingError(message:String) + { + super(message); + } + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // responder + //---------------------------------- + + /** + * @private + */ + private var _responders:Array; + + /** + * An array of IResponder handlers that will be called when + * the asynchronous request completes. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get responders():Array + { + return _responders; + } + + //-------------------------------------------------------------------------- + // + // Methods + // + //-------------------------------------------------------------------------- + + /** + *addResponder adds a responder to an Array of responders.
+ * The object assigned to the responder parameter must implement the
+ * mx.rpc.IResponder interface.
+ *
+ * @param responder A handler which will be called when the asynchronous request completes.
+ *
+ * @see mx.rpc.IResponder
+ * @see mx.collections.ItemResponder
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function addResponder(responder:IResponder):void
+ {
+ if (!_responders)
+ _responders = [];
+
+ _responders.push(responder);
+ }
+}
+
+}
diff --git a/src/mx/collections/errors/SortError.as b/src/mx/collections/errors/SortError.as
new file mode 100644
index 00000000..431bf8a2
--- /dev/null
+++ b/src/mx/collections/errors/SortError.as
@@ -0,0 +1,50 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.collections.errors
+{
+
+/**
+ * This error is thrown when a Sort class is not configured properly;
+ * for example, if the find criteria are invalid.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class SortError extends Error
+{
+ include "../../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param message A message providing information about the error cause.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function SortError(message:String)
+ {
+ super(message);
+ }
+}
+
+}
diff --git a/src/mx/core/AdvancedLayoutFeatures.as b/src/mx/core/AdvancedLayoutFeatures.as
new file mode 100644
index 00000000..8965da85
--- /dev/null
+++ b/src/mx/core/AdvancedLayoutFeatures.as
@@ -0,0 +1,1138 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2003-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+package mx.core
+{
+ import flash.events.Event;
+ import flash.geom.Matrix;
+ import flash.geom.Matrix3D;
+ import flash.geom.Point;
+ import flash.geom.Vector3D;
+ import flash.system.Capabilities;
+
+ import mx.geom.CompoundTransform;
+ import mx.geom.TransformOffsets;
+
+ use namespace mx_internal;
+
+ /**
+ * @private
+ * Transform Offsets can be assigned to any Component or GraphicElement to modify the transform
+ * of the object beyond where its parent layout places it.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public class AdvancedLayoutFeatures implements IAssetLayoutFeatures
+ {
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function AdvancedLayoutFeatures()
+ {
+ layout = new CompoundTransform();
+ }
+
+
+
+ /**
+ * @private
+ * a flag for use by the owning object indicating whether the owning object has a pending update
+ * to the computed matrix. it is the owner's responsibility to set this flag.
+ */
+ public var updatePending:Boolean = false;
+
+ /**
+ * storage for the depth value. Layering is considered 'advanced' layout behavior, and not something
+ * that gets used by the majority of the components out there. So if a component has a non-zero depth,
+ * it will allocate a AdvancedLayoutFeatures object and store the value here.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var depth:Number = 0;
+
+ /**
+ * @private
+ * slots for the various 2D and 3D matrices for layout, offset, and computed transforms. Note that
+ * these are only allocated and computed on demand -- many component instances will never use a 3D
+ * matrix, for example.
+ */
+ protected var _computedMatrix:Matrix;
+ protected var _computedMatrix3D:Matrix3D;
+
+ /**
+ * @private
+ * the layout visible transform as defined by the user and parent layout.
+ */
+ protected var layout:CompoundTransform;
+
+ /**
+ * @private
+ * offset values applied by the user
+ */
+ private var _postLayoutTransformOffsets:TransformOffsets;
+
+ /**
+ * @private
+ * bit field flags for indicating which transforms are valid -- the layout properties, the matrices,
+ * and the 3D matrices. Since developers can set any of the three programmatically, the last one set
+ * will always be valid, and the others will be invalid until validated on demand.
+ */
+ private static const COMPUTED_MATRIX_VALID:uint = 0x1;
+ private static const COMPUTED_MATRIX3D_VALID:uint = 0x2;
+
+ /**
+ * @private
+ * general storage for all of our flags.
+ */
+ private var _flags:uint = 0;
+
+ /**
+ * @private
+ * static data used by utility methods below
+ */
+ private static var reVT:Vector3D = new Vector3D(0,0,0);
+ private static var reVR:Vector3D = new Vector3D(0,0,0);
+ private static var reVS:Vector3D = new Vector3D(1,1,1);
+
+ private static var reV:Vector.position and postLayoutPosition
+ * parameters, if they are non-null.
+ *
+ * @param propertyIs3D A boolean reflecting whether the calculation needs
+ * to take into account the 3D matrix of the object.
+ * @param localPoint The point to be transformed, specified in the
+ * local coordinates of the object.
+ * @position A Vector3D point that will hold the pre-layout
+ * result. If null, the parameter is ignored.
+ * @postLayoutPosition A Vector3D point that will hold the post-layout
+ * result. If null, the parameter is ignored.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function transformPointToParent(propertyIs3D:Boolean,
+ localPosition:Vector3D, position:Vector3D,
+ postLayoutPosition:Vector3D):void
+ {
+ var transformedV:Vector3D;
+ var transformedP:Point;
+ tempLocalPosition =
+ localPosition ?
+ localPosition.clone() :
+ new Vector3D();
+
+ if (is3D || propertyIs3D)
+ {
+ if (position != null)
+ {
+ transformedV = transformVector(layoutMatrix3D, tempLocalPosition);
+ position.x = transformedV.x;
+ position.y = transformedV.y;
+ position.z = transformedV.z;
+ }
+
+ if (postLayoutPosition != null)
+ {
+ // computedMatrix factor in stretchXY, so divide it out of position first
+ tempLocalPosition.x /= stretchX;
+ tempLocalPosition.y /= stretchY;
+ transformedV = transformVector(computedMatrix3D, tempLocalPosition);
+ postLayoutPosition.x = transformedV.x;
+ postLayoutPosition.y = transformedV.y;
+ postLayoutPosition.z = transformedV.z;
+ }
+ }
+ else
+ {
+ var localP:Point = new Point(tempLocalPosition.x,
+ tempLocalPosition.y);
+ if (position != null)
+ {
+ transformedP = layoutMatrix.transformPoint(localP);
+ position.x = transformedP.x;
+ position.y = transformedP.y;
+ position.z = 0;
+ }
+
+ if (postLayoutPosition != null)
+ {
+ // computedMatrix factor in stretchXY, so divide it out of position first
+ localP.x /= stretchX;
+ localP.y /= stretchY;
+ transformedP = computedMatrix.transformPoint(localP);
+ postLayoutPosition.x = transformedP.x;
+ postLayoutPosition.y = transformedP.y;
+ postLayoutPosition.z = 0;
+ }
+ }
+ }
+
+ /**
+ * @private
+ * call when you've changed the inputs to the computed transform to make
+ * any adjustments to keep a particular point fixed in parent coordinates.
+ */
+ private function completeTransformCenterAdjustment(changeIs3D:Boolean,
+ transformCenter:Vector3D, targetPosition:Vector3D,
+ targetPostLayoutPosition:Vector3D):void
+ {
+ // TODO (chaase): optimize for transformCenter == (0,0,0)
+ if (is3D || changeIs3D)
+ {
+ if (targetPosition != null)
+ {
+ var adjustedLayoutCenterV:Vector3D = transformVector(layoutMatrix3D, transformCenter);
+ if (adjustedLayoutCenterV.equals(targetPosition) == false)
+ {
+ layout.translateBy(targetPosition.x - adjustedLayoutCenterV.x,
+ targetPosition.y - adjustedLayoutCenterV.y,
+ targetPosition.z - adjustedLayoutCenterV.z);
+ invalidate();
+ }
+ }
+ if (targetPostLayoutPosition != null && _postLayoutTransformOffsets != null)
+ {
+ // computedMatrix factor in stretchXY, so divide it out of transform center first
+ var tmpPos:Vector3D = new Vector3D(transformCenter.x, transformCenter.y, transformCenter.z);
+ tmpPos.x /= stretchX;
+ tmpPos.y /= stretchY;
+ var adjustedComputedCenterV:Vector3D = transformVector(computedMatrix3D, tmpPos);
+ if (adjustedComputedCenterV.equals(targetPostLayoutPosition) == false)
+ {
+ postLayoutTransformOffsets.x +=targetPostLayoutPosition.x - adjustedComputedCenterV.x;
+ postLayoutTransformOffsets.y += targetPostLayoutPosition.y - adjustedComputedCenterV.y;
+ postLayoutTransformOffsets.z += targetPostLayoutPosition.z - adjustedComputedCenterV.z;
+ invalidate();
+ }
+ }
+ }
+ else
+ {
+ var transformCenterP:Point = new Point(transformCenter.x,transformCenter.y);
+ if (targetPosition != null)
+ {
+ var currentPositionP:Point = layoutMatrix.transformPoint(transformCenterP);
+ if (currentPositionP.x != targetPosition.x ||
+ currentPositionP.y != targetPosition.y)
+ {
+ layout.translateBy(targetPosition.x - currentPositionP.x,
+ targetPosition.y - currentPositionP.y, 0);
+ invalidate();
+ }
+ }
+
+ if (targetPostLayoutPosition != null && _postLayoutTransformOffsets != null)
+ {
+ // computedMatrix factor in stretchXY, so divide it out of transform center first
+ transformCenterP.x /= stretchX;
+ transformCenterP.y /= stretchY;
+ var currentPostLayoutPosition:Point =
+ computedMatrix.transformPoint(transformCenterP);
+ if (currentPostLayoutPosition.x != targetPostLayoutPosition.x ||
+ currentPostLayoutPosition.y != targetPostLayoutPosition.y)
+ {
+ _postLayoutTransformOffsets.x += targetPostLayoutPosition.x - currentPostLayoutPosition.x;
+ _postLayoutTransformOffsets.y += targetPostLayoutPosition.y - currentPostLayoutPosition.y;
+ invalidate();
+ }
+ }
+ }
+ }
+
+ private static var staticTranslation:Vector3D = new Vector3D();
+ private static var staticOffsetTranslation:Vector3D = new Vector3D();
+
+ /**
+ * A utility method to update the rotation and scale of the transform
+ * while keeping a particular point, specified in the component's own
+ * coordinate space, fixed in the parent's coordinate space. This
+ * function will assign the rotation and scale values provided, then
+ * update the x/y/z properties as necessary to keep tx/ty/tz fixed.
+ * @param transformCenter the point, in the component's own coordinates,
+ * to keep fixed relative to its parent.
+ * @param rotation the new values for the rotation of the transform
+ * @param scale the new values for the scale of the transform
+ * @param translation the new values for the translation of the transform
+ */
+ public function transformAround(transformCenter:Vector3D,
+ scale:Vector3D,
+ rotation:Vector3D,
+ transformCenterPosition:Vector3D,
+ postLayoutScale:Vector3D = null,
+ postLayoutRotation:Vector3D = null,
+ postLayoutTransformCenterPosition:Vector3D = null):void
+ {
+ var is3D:Boolean = (scale != null && scale.z != 1) ||
+ (rotation != null && ((rotation.x != 0 ) || (rotation.y != 0))) ||
+ (transformCenterPosition != null && transformCenterPosition.z != 0) ||
+ (postLayoutScale != null && postLayoutScale.z != 1) ||
+ (postLayoutRotation != null &&
+ (postLayoutRotation.x != 0 || postLayoutRotation.y != 0)) ||
+ (postLayoutTransformCenterPosition != null && postLayoutTransformCenterPosition.z != 0);
+
+ var needOffsets:Boolean = _postLayoutTransformOffsets == null &&
+ (postLayoutScale != null || postLayoutRotation != null ||
+ postLayoutTransformCenterPosition != null);
+ if (needOffsets)
+ _postLayoutTransformOffsets = new TransformOffsets();
+
+ // now if they gave us a non-trivial transform center, and didn't tell us where they want it,
+ // we need to calculate where it is so that we can make sure we keep it there.
+ if (transformCenter != null &&
+ (transformCenterPosition == null || postLayoutTransformCenterPosition == null))
+ {
+ transformPointToParent(is3D, transformCenter, staticTranslation,
+ staticOffsetTranslation);
+ if (postLayoutTransformCenterPosition == null && transformCenterPosition != null)
+ {
+ staticOffsetTranslation.x = transformCenterPosition.x + staticOffsetTranslation.x - staticTranslation.x;
+ staticOffsetTranslation.y = transformCenterPosition.y + staticOffsetTranslation.y - staticTranslation.y;
+ staticOffsetTranslation.z = transformCenterPosition.z + staticOffsetTranslation.z - staticTranslation.z;
+ }
+
+ }
+ // if targetPosition/postLayoutTargetPosition is null here, it might be because the caller passed in
+ // requested values, so we haven't calculated it yet. So that means our target position is the values
+ // they passed in.
+ var targetPosition:Vector3D = (transformCenterPosition == null)? staticTranslation:transformCenterPosition;
+ var postLayoutTargetPosition:Vector3D = (postLayoutTransformCenterPosition == null)? staticOffsetTranslation:postLayoutTransformCenterPosition;
+
+ // now update our transform values.
+ if (rotation != null)
+ {
+ if (!isNaN(rotation.x))
+ layout.rotationX = rotation.x;
+ if (!isNaN(rotation.y))
+ layout.rotationY = rotation.y;
+ if (!isNaN(rotation.z))
+ layout.rotationZ = rotation.z;
+ }
+ if (scale != null)
+ {
+ if (!isNaN(scale.x))
+ layout.scaleX = scale.x;
+ if (!isNaN(scale.y))
+ layout.scaleY = scale.y;
+ if (!isNaN(scale.z))
+ layout.scaleZ = scale.z;
+ }
+
+ if (postLayoutRotation != null)
+ {
+ _postLayoutTransformOffsets.rotationX = postLayoutRotation.x;
+ _postLayoutTransformOffsets.rotationY = postLayoutRotation.y;
+ _postLayoutTransformOffsets.rotationZ = postLayoutRotation.z;
+ }
+ if (postLayoutScale != null)
+ {
+ _postLayoutTransformOffsets.scaleX = postLayoutScale.x;
+ _postLayoutTransformOffsets.scaleY = postLayoutScale.y;
+ _postLayoutTransformOffsets.scaleZ = postLayoutScale.z;
+ }
+
+ // if they didn't pass us a transform center,
+ // then we assume it's the origin. In that case, it's trivially easy
+ // to make sure the origin is at a particular point...we simply set
+ // the transformCenterPosition portion of our transforms to that point.
+ if (transformCenter == null)
+ {
+ if (transformCenterPosition != null)
+ {
+ layout.x = transformCenterPosition.x;
+ layout.y = transformCenterPosition.y;
+ layout.z = transformCenterPosition.z;
+ }
+ if (postLayoutTransformCenterPosition != null)
+ {
+ _postLayoutTransformOffsets.x = postLayoutTransformCenterPosition.x - layout.x;
+ _postLayoutTransformOffsets.y = postLayoutTransformCenterPosition.y - layout.y;
+ _postLayoutTransformOffsets.z = postLayoutTransformCenterPosition.z - layout.z;
+ }
+ }
+ invalidate();
+
+ // if they did pass in a transform center, go do the adjustments necessary to keep it fixed in place.
+ if (transformCenter != null)
+ completeTransformCenterAdjustment(is3D, transformCenter,
+ targetPosition, postLayoutTargetPosition);
+
+
+ }
+
+}
+}
+
diff --git a/src/mx/core/BitmapAsset.as b/src/mx/core/BitmapAsset.as
new file mode 100644
index 00000000..68a72fd4
--- /dev/null
+++ b/src/mx/core/BitmapAsset.as
@@ -0,0 +1,779 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+import flash.display.BitmapData;
+import flash.display.DisplayObjectContainer;
+import flash.events.Event;
+import flash.geom.Point;
+import flash.system.ApplicationDomain;
+
+/**
+ * BitmapAsset is a subclass of the flash.display.Bitmap class
+ * which represents bitmap images that you embed in a Flex application.
+ * It implements the IFlexDisplayObject interface, which makes it
+ * possible for an embedded bitmap image to be displayed in an Image control,
+ * or to be used as a container background or a component skin.
+ *
+ * The bitmap image that you're embedding can be in a JPEG, GIF, + * or PNG file. + * You can also embed a bitmap symbol that is in a SWF file produced + * by Flash. + * In each of these cases, the MXML compiler autogenerates a class + * that extends BitmapAsset to represent the embedded bitmap image.
+ * + *You don't generally have to use the BitmapAsset class directly + * when you write a Flex application. + * For example, you can embed a GIF file and display the image + * in an Image control by writing the gollowing:
+ * + *+ * <mx:Image id="logo" source="@Embed(source='Logo.gif')"/>+ * + *
or use it as the application's background image in CSS syntax + * by writing
+ * + *
+ * <fx:Style>
+ * @namespace mx "library://ns.adobe.com/flex/mx"
+ * mx|Application {
+ * backgroundImage: Embed(source="Logo.gif")
+ * }
+ * <fx:Style/>
+ *
+ * without having to understand that the MXML compiler has created + * a subclass of BitmapAsset for you.
+ * + *However, it may be useful to understand what is happening
+ * at the ActionScript level.
+ * To embed a bitmap image in ActionScript, you declare a variable
+ * of type Class, and put [Embed] metadata on it.
+ * For example, you embed a GIF file like this:
+ * [Bindable] + * [Embed(source="Logo.gif")] + * private var logoClass:Class;+ * + *
The MXML compiler sees the .gif extension, transcodes the GIF data
+ * into the bitmap format that the player uses, autogenerates
+ * a subclass of the BitmapAsset class, and sets your variable
+ * to be a reference to this autogenerated class.
+ * You can then use this class reference to create instances of the
+ * BitmapAsset using the new operator, and you can use
+ * APIs of the BitmapAsset class on them:
+ * var logo:BitmapAsset = BitmapAsset(new logoClass()); + * logo.bitmapData.noise(4);+ * + *
However, you rarely need to create BitmapAsset instances yourself
+ * because image-related properties and styles can simply be set to an
+ * image-producing class, and components will create image instances
+ * as necessary.
+ * For example, to display this image in an Image control, you can
+ * set the Image's source property to logoClass.
+ * In MXML you could do this as follows:
+ * <mx:Image id="logo" source="{logoClass}"/>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class BitmapAsset extends FlexBitmap
+ implements IFlexAsset, IFlexDisplayObject, ILayoutDirectionElement
+{
+ include "../core/Version.as";
+
+ // Softlink FlexVersion and MatrixUtil to remove dependencies of embeds on
+ // framework classes. This helps to reduce swf size in AS-only projects.
+ private static var FlexVersionClass:Class;
+ private static var MatrixUtilClass:Class;
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param bitmapData The data for the bitmap image.
+ *
+ * @param pixelSnapping Whether or not the bitmap is snapped
+ * to the nearest pixel.
+ *
+ * @param smoothing Whether or not the bitmap is smoothed when scaled.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function BitmapAsset(bitmapData:BitmapData = null,
+ pixelSnapping:String = "auto",
+ smoothing:Boolean = false)
+ {
+ super(bitmapData, pixelSnapping, smoothing);
+
+ if (FlexVersionClass == null)
+ {
+ var appDomain:ApplicationDomain = ApplicationDomain.currentDomain;
+ if (appDomain.hasDefinition("mx.core::FlexVersion"))
+ FlexVersionClass = Class(appDomain.getDefinition("mx.core::FlexVersion"));
+ }
+
+ if (FlexVersionClass && FlexVersionClass["compatibilityVersion"] >= FlexVersionClass["VERSION_4_0"])
+ this.addEventListener(Event.ADDED, addedHandler);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ // Softlink AdvancedLayoutFeatures to remove dependencies of embeds on
+ // framework classes. This helps to reduce swf size in AS-only projects.
+ private var layoutFeaturesClass:Class;
+ private var layoutFeatures:IAssetLayoutFeatures;
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // x
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get x():Number
+ {
+ // TODO(hmuller): by default get x returns transform.matrix.tx rounded to the nearest 20th.
+ // should do the same here, if we're returning layoutFeatures.layoutX.
+ return (layoutFeatures == null) ? super.x : layoutFeatures.layoutX;
+ }
+
+ /**
+ * @private
+ */
+ override public function set x(value:Number):void
+ {
+ if (x == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.x = value;
+ }
+ else
+ {
+ layoutFeatures.layoutX = value;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // y
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get y():Number
+ {
+ return (layoutFeatures == null) ? super.y : layoutFeatures.layoutY;
+ }
+
+ /**
+ * @private
+ */
+ override public function set y(value:Number):void
+ {
+ if (y == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.y = value;
+ }
+ else
+ {
+ layoutFeatures.layoutY = value;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // z
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get z():Number
+ {
+ return (layoutFeatures == null) ? super.z : layoutFeatures.layoutZ;
+ }
+
+ /**
+ * @private
+ */
+ override public function set z(value:Number):void
+ {
+ if (z == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.z = value;
+ }
+ else
+ {
+ layoutFeatures.layoutZ = value;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // width
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get width():Number
+ {
+ if (layoutFeatures == null)
+ return super.width;
+
+ // Return bounding box width in mirroring case
+ var p:Point;
+ if (MatrixUtilClass != null)
+ p = MatrixUtilClass["transformSize"](layoutFeatures.layoutWidth, _height, transform.matrix);
+
+ return p ? p.x : super.width;
+ }
+
+ /**
+ * @private
+ */
+ override public function set width(value:Number):void
+ {
+ if (width == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.width = value;
+ }
+ else
+ {
+ layoutFeatures.layoutWidth = value;
+ // Calculate scaleX based on initial width. We set scaleX
+ // here because resizing a BitmapAsset normally would adjust
+ // the scale to match.
+ layoutFeatures.layoutScaleX = measuredWidth != 0 ? value / measuredWidth : 0;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // height
+ //----------------------------------
+
+ private var _height:Number;
+
+ /**
+ * @private
+ */
+ override public function get height():Number
+ {
+
+ if (layoutFeatures == null)
+ return super.height;
+
+ // Return bounding box height in mirroring case
+ var p:Point;
+ if (MatrixUtilClass != null)
+ p = MatrixUtilClass["transformSize"](layoutFeatures.layoutWidth, _height, transform.matrix);
+
+ return p ? p.y : super.height;
+ }
+
+ /**
+ * @private
+ */
+ override public function set height(value:Number):void
+ {
+ if (height == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.height = value;
+ }
+ else
+ {
+ _height = value;
+ // Calculate scaleY based on initial height. We set scaleY
+ // here because resizing a BitmapAsset normally would adjust
+ // the scale to match.
+ layoutFeatures.layoutScaleY = measuredHeight != 0 ? value / measuredHeight : 0;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // rotation
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get rotationX():Number
+ {
+ return (layoutFeatures == null) ? super.rotationX : layoutFeatures.layoutRotationX;
+ }
+
+ /**
+ * @private
+ */
+ override public function set rotationX(value:Number):void
+ {
+ if (rotationX == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.rotationX = value;
+ }
+ else
+ {
+ layoutFeatures.layoutRotationX = value;
+ validateTransformMatrix();
+ }
+ }
+ /**
+ * @private
+ */
+ override public function get rotationY():Number
+ {
+ return (layoutFeatures == null) ? super.rotationY : layoutFeatures.layoutRotationY;
+ }
+
+ /**
+ * @private
+ */
+ override public function set rotationY(value:Number):void
+ {
+ if (rotationY == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.rotationY = value;
+ }
+ else
+ {
+ layoutFeatures.layoutRotationY = value;
+ validateTransformMatrix();
+ }
+ }
+
+ /**
+ * @private
+ */
+ override public function get rotationZ():Number
+ {
+ return (layoutFeatures == null) ? super.rotationZ : layoutFeatures.layoutRotationZ;
+ }
+
+ /**
+ * @private
+ */
+ override public function set rotationZ(value:Number):void
+ {
+ if (rotationZ == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.rotationZ = value;
+ }
+ else
+ {
+ layoutFeatures.layoutRotationZ = value;
+ validateTransformMatrix();
+ }
+ }
+
+ /**
+ * @private
+ */
+ override public function get rotation():Number
+ {
+ return (layoutFeatures == null) ? super.rotation : layoutFeatures.layoutRotationZ;
+ }
+
+ /**
+ * @private
+ */
+ override public function set rotation(value:Number):void
+ {
+ if (rotation == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.rotation = value;
+ }
+ else
+ {
+ layoutFeatures.layoutRotationZ = value;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // scaleX
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get scaleX():Number
+ {
+ return (layoutFeatures == null) ? super.scaleX : layoutFeatures.layoutScaleX;
+ }
+
+ /**
+ * @private
+ */
+ override public function set scaleX(value:Number):void
+ {
+ if (scaleX == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.scaleX = value;
+ }
+ else
+ {
+ layoutFeatures.layoutScaleX = value;
+ layoutFeatures.layoutWidth = Math.abs(value) * measuredWidth;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // scaleY
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get scaleY():Number
+ {
+ return (layoutFeatures == null) ? super.scaleY : layoutFeatures.layoutScaleY;
+ }
+
+ /**
+ * @private
+ */
+ override public function set scaleY(value:Number):void
+ {
+ if (scaleY == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.scaleY = value;
+ }
+ else
+ {
+ layoutFeatures.layoutScaleY = value;
+ _height = Math.abs(value) * measuredHeight;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // scaleZ
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get scaleZ():Number
+ {
+ return (layoutFeatures == null) ? super.scaleZ : layoutFeatures.layoutScaleZ;
+ }
+
+ /**
+ * @private
+ */
+ override public function set scaleZ(value:Number):void
+ {
+ if (scaleZ == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.scaleZ = value;
+ }
+ else
+ {
+ layoutFeatures.layoutScaleZ = value;
+ validateTransformMatrix();
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // layoutDirection
+ //----------------------------------
+
+ // Use "ltr" instead of LayoutDirection.LTR to avoid depending
+ // on that framework class.
+ private var _layoutDirection:String = "ltr";
+
+ [Inspectable(category="General", enumeration="ltr,rtl")]
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ public function get layoutDirection():String
+ {
+ return _layoutDirection;
+ }
+
+ public function set layoutDirection(value:String):void
+ {
+ if (value == _layoutDirection)
+ return;
+
+ _layoutDirection = value;
+ invalidateLayoutDirection();
+ }
+
+ //----------------------------------
+ // measuredHeight
+ //----------------------------------
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get measuredHeight():Number
+ {
+ if (bitmapData)
+ return bitmapData.height
+
+ return 0;
+ }
+
+ //----------------------------------
+ // measuredWidth
+ //----------------------------------
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get measuredWidth():Number
+ {
+ if (bitmapData)
+ return bitmapData.width;
+
+ return 0;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ public function invalidateLayoutDirection():void
+ {
+ var p:DisplayObjectContainer = parent;
+
+ // We check the closest parent's layoutDirection property
+ // to create or destroy layoutFeatures if needed.
+ while (p)
+ {
+ if (p is ILayoutDirectionElement)
+ {
+ // mirror is true if our layoutDirection differs from our parent's.
+ var mirror:Boolean = _layoutDirection != null &&
+ ILayoutDirectionElement(p).layoutDirection != null &&
+ (_layoutDirection != ILayoutDirectionElement(p).layoutDirection);
+
+ // If our layoutDirection is different from our parent's and if it used to
+ // be the same, create layoutFeatures to handle mirroring.
+ if (mirror && layoutFeatures == null)
+ {
+ initAdvancedLayoutFeatures();
+ if (layoutFeatures != null)
+ {
+ layoutFeatures.mirror = mirror;
+ validateTransformMatrix();
+ }
+ }
+ else if (!mirror && layoutFeatures)
+ {
+ // If our layoutDirection is not different from our parent's and if
+ // it used to be different, then recover our matrix and remove layoutFeatures.
+ layoutFeatures.mirror = mirror;
+ validateTransformMatrix();
+ layoutFeatures = null;
+ }
+
+ break;
+ }
+
+ p = p.parent;
+ }
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function move(x:Number, y:Number):void
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function setActualSize(newWidth:Number, newHeight:Number):void
+ {
+ width = newWidth;
+ height = newHeight;
+ }
+
+ /**
+ * @private
+ */
+ private function addedHandler(event:Event):void
+ {
+ invalidateLayoutDirection();
+ }
+
+ /**
+ * @private
+ * Initializes AdvancedLayoutFeatures for this asset when mirroring.
+ */
+ private function initAdvancedLayoutFeatures():void
+ {
+ // Get AdvancedLayoutFeatures if it exists.
+ if (layoutFeaturesClass == null)
+ {
+ var appDomain:ApplicationDomain = ApplicationDomain.currentDomain;
+
+ if (appDomain.hasDefinition("mx.core::AdvancedLayoutFeatures"))
+ layoutFeaturesClass = Class(appDomain.getDefinition("mx.core::AdvancedLayoutFeatures"));
+
+ // Get MatrixUtil class if it exists
+ if (MatrixUtilClass == null)
+ {
+ if (appDomain.hasDefinition("mx.utils::MatrixUtil"))
+ MatrixUtilClass = Class(appDomain.getDefinition("mx.utils::MatrixUtil"));
+ }
+ }
+
+ if (layoutFeaturesClass != null)
+ {
+ var features:IAssetLayoutFeatures = new layoutFeaturesClass();
+
+ features.layoutScaleX = scaleX;
+ features.layoutScaleY = scaleY;
+ features.layoutScaleZ = scaleZ;
+ features.layoutRotationX = rotationX;
+ features.layoutRotationY = rotationY;
+ features.layoutRotationZ = rotation;
+ features.layoutX = x;
+ features.layoutY = y;
+ features.layoutZ = z;
+ features.layoutWidth = width; // for the mirror transform
+ _height = height; // for backing storage
+ layoutFeatures = features;
+ }
+ }
+
+ /**
+ * @private
+ * Applies the transform matrix calculated by AdvancedLayoutFeatures
+ * so that this bitmap will not be mirrored if a parent is mirrored.
+ */
+ private function validateTransformMatrix():void
+ {
+ if (layoutFeatures != null)
+ {
+ if (layoutFeatures.is3D)
+ super.transform.matrix3D = layoutFeatures.computedMatrix3D;
+ else
+ super.transform.matrix = layoutFeatures.computedMatrix;
+ }
+ }
+}
+
+}
diff --git a/src/mx/core/ByteArrayAsset.as b/src/mx/core/ByteArrayAsset.as
new file mode 100644
index 00000000..f5a2fc7e
--- /dev/null
+++ b/src/mx/core/ByteArrayAsset.as
@@ -0,0 +1,95 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+import flash.utils.ByteArray;
+
+/**
+ * ByteArrayAsset is a subclass of the flash.utils.ByteArray class
+ * which represents an arbitrary sequence of byte data that you embed
+ * in a Flex application.
+ *
+ * The byte data that you are embedding can be in any kind of file, + * and the entire file is always embedded. + * You cannot embed the bytes of a particular asset that is in a SWF file, + * although you can embed an entire SWF file.
+ * + *The MXML compiler autogenerates a class that extends ByteArrayAsset + * to represent the embedded data.
+ * + *To embed an arbitrary file, you declare a variable of type Class,
+ * and put [Embed] metadata on it, using the MIME type
+ * application/octet-stream.
+ * For example, you embed a text file like this:
+ * [Bindable] + * [Embed(source="Story.txt", mimeType="application/octet-stream")] + * private var storyClass:Class; + *+ * + *
The compiler autogenerates a subclass of the ByteArrayAsset class
+ * and sets your variable to be a reference to this autogenerated class.
+ * You can then use this class reference to create instances of the
+ * ByteArrayAsset using the new operator, and you can extract
+ * information from the byte array using methods of the ByteArray class:
+ * var storyByteArray:ByteArrayAsset = ByteArrayAsset(new storyClass()); + * var story:String = storyByteArray.readUTFBytes(storyByteArray.length); + *+ * + *
You must specify that the MIME type for the embedding is
+ * application/octet-stream, which causes the byte data
+ * to be embedded "as is", with no interpretation.
+ * It also causes the autogenerated class to extend ByteArrayAsset
+ * rather than another asset class.
For example, if you embed a PNG file without specifying this
+ * MIME type, the PNG data will be automatically transcoded
+ * into the bitmap format used by the player, and a subclass
+ * of BitmapAsset will be autogenerated to represent it.
+ * But if you specify the MIME type as application/octet-stream,
+ * then no transcoding will occur, the PNG data will be embedded
+ * as is, and the autogenerated class will extend ByteArrayAsset.
You specify a generator class when you construct
+ * the factory object.
+ * Then you set the properties property on the factory object.
+ * Flex uses the factory object to generate instances by calling
+ * the factory object's newInstance() method.
The newInstance() method creates a new instance
+ * of the generator class, and sets the properties specified
+ * by properties in the new instance.
+ * If you need to further customize the generated instances,
+ * you can override the newInstance() method.
The ClassFactory class implements the IFactory interface.
+ * Therefore it lets you create objects that can be assigned to properties
+ * of type IFactory, such as the itemRenderer property of a List control
+ * or the itemEditor property of a DataGrid control.
For example, suppose you write an item renderer class named
+ * ProductRenderer containing
+ * a showProductImage property which can be true
+ * or false.
+ * If you want to make a List control use this renderer, and have each renderer
+ * instance display a product image, you would write the following code:
+ * var productRenderer:ClassFactory = new ClassFactory(ProductRenderer);
+ * productRenderer.properties = { showProductImage: true };
+ * myList.itemRenderer = productRenderer;
+ *
+ * The List control calls the newInstance() method on the
+ * itemRenderer to create individual instances of ProductRenderer,
+ * each with showProductImage property set to true.
+ * If you want a different List control to omit the product images, you use
+ * the ProductRenderer class to create another ClassFactory
+ * with the properties property set to
+ * { showProductImage: false }.
Using the properties property to configure the instances
+ * can be powerful, since it allows a single generator class to be used
+ * in different ways.
+ * However, it is very common to create non-configurable generator classes
+ * which require no properties to be set.
+ * For this reason, MXML lets you use the following syntax:
+ * <mx:List id="myList" itemRenderer="ProductRenderer">+ * + *
The MXML compiler automatically creates the ClassFactory instance + * for you.
+ * + * @see mx.core.IFactory + * @see mx.controls.List + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class ClassFactory implements IFactory +{ + include "../core/Version.as"; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @param generator The Class that thenewInstance() method uses
+ * to generate objects from this factory object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function ClassFactory(generator:Class = null)
+ {
+ super();
+
+ this.generator = generator;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // generator
+ //----------------------------------
+
+ /**
+ * The Class that the newInstance() method uses
+ * to generate objects from this factory object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var generator:Class;
+
+ //----------------------------------
+ // properties
+ //----------------------------------
+
+ /**
+ * An Object whose name/value pairs specify the properties to be set
+ * on each object generated by the newInstance() method.
+ *
+ * For example, if you set properties to
+ * { text: "Hello", width: 100 }, then every instance
+ * of the generator class that is generated by calling
+ * newInstance() will have its text set to
+ * "Hello" and its width set to
+ * 100.
generator class,
+ * with the properties specified by properties.
+ *
+ * This method implements the newInstance() method
+ * of the IFactory interface.
getInstance() method to
+ * create an instance of the class when it is first needed and get
+ * a reference to the instance thereafter.
+ *
+ * @see DeferredInstanceFromFunction
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class DeferredInstanceFromClass implements ITransientDeferredInstance
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param generator The class whose instance the getInstance()
+ * method creates and returns.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function DeferredInstanceFromClass(generator:Class)
+ {
+ super();
+
+ this.generator = generator;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * The generator class.
+ */
+ private var generator:Class;
+
+ /**
+ * @private
+ * The generated value.
+ */
+ private var instance:Object = null;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Creates and returns an instance of the class specified in the
+ * DeferredInstanceFromClass constructor, if it does not yet exist;
+ * otherwise, returns the already-created class instance.
+ *
+ * @return An instance of the class specified in the
+ * DeferredInstanceFromClass constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function getInstance():Object
+ {
+ if (!instance)
+ instance = new generator();
+
+ return instance;
+ }
+
+ /**
+ * Resets the state of our factory to the initial, uninitialized state.
+ * The reference to our cached instance is cleared.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 4
+ */
+ public function reset():void
+ {
+ instance = null;
+ }
+}
+
+}
diff --git a/src/mx/core/DeferredInstanceFromFunction.as b/src/mx/core/DeferredInstanceFromFunction.as
new file mode 100644
index 00000000..8e06affe
--- /dev/null
+++ b/src/mx/core/DeferredInstanceFromFunction.as
@@ -0,0 +1,137 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+/**
+ * A deferred instance factory that uses a generator function
+ * to create an instance of the required object.
+ * An application uses the getInstance() method to
+ * create an instance of an object when it is first needed and get
+ * a reference to the object thereafter.
+ *
+ * @see DeferredInstanceFromClass
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class DeferredInstanceFromFunction implements ITransientDeferredInstance
+{
+ //include "../core/Version.as";
+
+ import mx.core.mx_internal;
+
+ /**
+ * @private
+ * Version string for this class.
+ */
+ mx_internal static const VERSION:String = "4.1.0.16076";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param generator A function that creates and returns an instance
+ * of the required object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function DeferredInstanceFromFunction(generator:Function,
+ destructor:Function = null )
+ {
+ super();
+
+ this.generator = generator;
+ this.destructor = destructor;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * The generator function.
+ */
+ private var generator:Function;
+
+ /**
+ * @private
+ * The generated value.
+ */
+ private var instance:Object = null;
+
+ /**
+ * @private
+ * An optional function used to cleanup outstanding
+ * references when reset() is invoked
+ */
+ private var destructor:Function;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Returns a reference to an instance of the desired object.
+ * If no instance of the required object exists, calls the function
+ * specified in this class' generator constructor parameter.
+ *
+ * @return An instance of the object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function getInstance():Object
+ {
+ if (!instance)
+ instance = generator();
+
+ return instance;
+ }
+
+ /**
+ * Resets the state of our factory to the initial, uninitialized state.
+ * The reference to our cached instance is cleared.
+ *
+ * @langversion 4.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 4
+ */
+ public function reset():void
+ {
+ instance = null;
+
+ if (destructor != null)
+ destructor();
+ }
+
+}
+
+}
diff --git a/src/mx/core/EdgeMetrics.as b/src/mx/core/EdgeMetrics.as
new file mode 100644
index 00000000..c20d2e25
--- /dev/null
+++ b/src/mx/core/EdgeMetrics.as
@@ -0,0 +1,193 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2004-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+/**
+ * The EdgeMetrics class specifies the thickness, in pixels,
+ * of the four edge regions around a visual component.
+ *
+ * The following Flex properties have values that are EdgeMetrics + * objects:
+ * + *borderMetrics property of the mx.core.Container and
+ * mx.skins.Border classes includes only the border in the calculations
+ * of the property values of the EdgeMetrics object.viewMetrics property of the mx.core.Container
+ * class, and of subclasses of the Container class, includes possible
+ * scrollbars and non-content elements -- such as a Panel container's
+ * header area and the area for a ControlBar component -- in the calculations
+ * of the property values of the EdgeMetrics object.viewMetricsAndPadding property of the
+ * mx.core.Container class includes the items listed for the
+ * viewMetrics property, plus the any areas defined by
+ * the margins of the container in the calculations of the
+ * property values of the EdgeMetrics object.These three properites all return a reference to the same
+ * EdgeMetrics object that the Container is using for its measurement
+ * and layout; they do not return a copy of this object.
+ * If you need a copy, call the clone() method.
left, top, right,
+ * and bottom properties.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const EMPTY:EdgeMetrics = new EdgeMetrics(0, 0, 0, 0);
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param left The width, in pixels, of the left edge region.
+ *
+ * @param top The height, in pixels, of the top edge region.
+ *
+ * @param right The width, in pixels, of the right edge region.
+ *
+ * @param bottom The height, in pixels, of the bottom edge region.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function EdgeMetrics(left:Number = 0, top:Number = 0,
+ right:Number = 0, bottom:Number = 0)
+ {
+ super();
+
+ this.left = left;
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // bottom
+ //----------------------------------
+
+ /**
+ * The height, in pixels, of the bottom edge region.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var bottom:Number;
+
+ //----------------------------------
+ // left
+ //----------------------------------
+
+ /**
+ * The width, in pixels, of the left edge region.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var left:Number;
+
+ //----------------------------------
+ // right
+ //----------------------------------
+
+ /**
+ * The width, in pixels, of the right edge region.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var right:Number;
+
+ //----------------------------------
+ // top
+ //----------------------------------
+
+ /**
+ * The height, in pixels, of the top edge region.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var top:Number;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Returns a copy of this EdgeMetrics object.
+ *
+ * @return A copy of this EdgeMetrics object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function clone():EdgeMetrics
+ {
+ return new EdgeMetrics(left, top, right, bottom);
+ }
+}
+
+}
diff --git a/src/mx/core/EventPriority.as b/src/mx/core/EventPriority.as
new file mode 100644
index 00000000..234cc876
--- /dev/null
+++ b/src/mx/core/EventPriority.as
@@ -0,0 +1,111 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+/**
+ * The EventPriority class defines constant values
+ * for the priority argument of the
+ * addEventListener() method of EventDispatcher.
+ *
+ * The higher the number, the higher the priority of the event listener.
+ * All listeners with priority N will be processed
+ * before listeners of priority N - 1.
+ * If two or more listeners share the same priority,
+ * they are processed in the order in which they were added.
Priorities can be positive, 0, or negative. + * The default priority is 0.
+ * + *You should not write code that depends on the numeric values + * of these constants. + * They are subject to change in future versions of Flex.
+ * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public final class EventPriority +{ + include "../core/Version.as"; + + //-------------------------------------------------------------------------- + // + // Class constants + // + //-------------------------------------------------------------------------- + + /** + * The CursorManager has handlers for mouse events + * which must be executed before other mouse event handlers, + * so they have a high priority. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public static const CURSOR_MANAGEMENT:int = 200; + + /** + * Autogenerated event handlers that evaluate data-binding expressions + * need to be executed before any others, so they have a higher priority + * than the default. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public static const BINDING:int = 100; + + /** + * Event handlers on component instances are executed with the default + * priority,0.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const DEFAULT:int = 0;
+
+ /**
+ * Some components listen to events that they dispatch on themselves
+ * and let other listeners call the preventDefault()
+ * method to tell the component not to perform a default action.
+ * Those components must listen with a lower priority than the default
+ * priority, so that the other handlers are executed first and have
+ * a chance to call preventDefault().
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const DEFAULT_HANDLER:int = -50;
+
+ /**
+ * Autogenerated event handlers that trigger effects are executed
+ * after other event handlers on component instances, so they have
+ * a lower priority than the default.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const EFFECT:int = -100;
+}
+
+}
diff --git a/src/mx/core/FlexBitmap.as b/src/mx/core/FlexBitmap.as
new file mode 100644
index 00000000..aab88429
--- /dev/null
+++ b/src/mx/core/FlexBitmap.as
@@ -0,0 +1,122 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+import flash.display.Bitmap;
+import flash.display.BitmapData;
+
+import mx.utils.NameUtil;
+
+/**
+ * FlexBitmap is a subclass of the Player's Bitmap class.
+ * It overrides the toString() method
+ * to return a string indicating the location of the object
+ * within the hierarchy of DisplayObjects in the application.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class FlexBitmap extends Bitmap
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * Sets the name property to a string
+ * returned by the createUniqueName()
+ * method of the mx.utils.NameUtils class.
+ * This string is the name of the object's class concatenated
+ * with an integer that is unique within the application,
+ * such as "FlexBitmap12".
"MyApp0.HBox5.FlexBitmap12",
+ * is built by the displayObjectToString() method
+ * of the mx.utils.NameUtils class from the name
+ * property of the object and its ancestors.
+ *
+ * @return A String indicating the location of this object
+ * within the DisplayObject hierarchy.
+ *
+ * @see flash.display.DisplayObject#name
+ * @see mx.utils.NameUtil#displayObjectToString()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function toString():String
+ {
+ return NameUtil.displayObjectToString(this);
+ }
+}
+
+}
diff --git a/src/mx/core/FlexSprite.as b/src/mx/core/FlexSprite.as
new file mode 100644
index 00000000..f749fe20
--- /dev/null
+++ b/src/mx/core/FlexSprite.as
@@ -0,0 +1,113 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+import flash.display.Sprite;
+import mx.utils.NameUtil;
+
+/**
+ * FlexSprite is a subclass of the Player's Sprite class
+ * and the superclass of UIComponent.
+ * It overrides the toString() method
+ * to return a string indicating the location of the object
+ * within the hierarchy of DisplayObjects in the application.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class FlexSprite extends Sprite
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * Sets the name property to a string
+ * returned by the createUniqueName()
+ * method of the mx.utils.NameUtils class.
This string is the name of the object's class concatenated
+ * with an integer that is unique within the application,
+ * such as "Button17".
"MyApp0.HBox5.Button17",
+ * is built by the displayObjectToString() method
+ * of the mx.utils.NameUtils class from the name
+ * property of the object and its ancestors.
+ *
+ * @return A String indicating the location of this object
+ * within the DisplayObject hierarchy.
+ *
+ * @see flash.display.DisplayObject#name
+ * @see mx.utils.NameUtil#displayObjectToString()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function toString():String
+ {
+ return NameUtil.displayObjectToString(this);
+ }
+}
+
+}
diff --git a/src/mx/core/IAssetLayoutFeatures.as b/src/mx/core/IAssetLayoutFeatures.as
new file mode 100644
index 00000000..83cea354
--- /dev/null
+++ b/src/mx/core/IAssetLayoutFeatures.as
@@ -0,0 +1,366 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2003-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+package mx.core
+{
+import flash.geom.Matrix;
+import flash.geom.Matrix3D;
+
+/**
+ * The IAssetLayoutFeatures interface defines the minimum properties and methods
+ * required for an Object to support advanced transforms in embedded assets.
+ *
+ * @see mx.core.AdvancedLayoutFeatures
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+public interface IAssetLayoutFeatures
+{
+
+ /**
+ * Layout transform convenience property. Represents the x value of the layout matrix used in layout and in
+ * the computed transform.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set layoutX(value:Number):void;
+
+ /**
+ * @private
+ */
+ function get layoutX():Number;
+
+ /**
+ * Layout transform convenience property. Represents the y value of the layout matrix used in layout and in
+ * the computed transform.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set layoutY(value:Number):void;
+
+ /**
+ * @private
+ */
+ function get layoutY():Number;
+
+ /**
+ * Layout transform convenience property. Represents the z value of the layout matrix used in layout and in
+ * the computed transform.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set layoutZ(value:Number):void;
+
+ /**
+ * @private
+ */
+ function get layoutZ():Number;
+
+ /**
+ * Used by the mirroring transform. See the mirror property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function get layoutWidth():Number;
+
+ /**
+ * @private
+ */
+ function set layoutWidth(value:Number):void;
+
+ //------------------------------------------------------------------------------
+
+ /**
+ * The x value of the point around which any rotation and scale is performed in both the layout and computed matrix.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set transformX(value:Number):void;
+ /**
+ * @private
+ */
+ function get transformX():Number;
+
+ /**
+ * The y value of the point around which any rotation and scale is performed in both the layout and computed matrix.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set transformY(value:Number):void;
+
+ /**
+ * @private
+ */
+ function get transformY():Number;
+
+ /**
+ * The z value of the point around which any rotation and scale is performed in both the layout and computed matrix.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set transformZ(value:Number):void;
+
+ /**
+ * @private
+ */
+ function get transformZ():Number;
+
+ //------------------------------------------------------------------------------
+
+ /**
+ * Layout transform convenience property. Represents the rotation around the X axis of the layout matrix used in layout and in
+ * the computed transform.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set layoutRotationX(value:Number):void;
+
+ /**
+ * @private
+ */
+ function get layoutRotationX():Number;
+
+ /**
+ * Layout transform convenience property. Represents the rotation around the Y axis of the layout matrix used in layout and in
+ * the computed transform.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set layoutRotationY(value:Number):void;
+
+ /**
+ * @private
+ */
+ function get layoutRotationY():Number;
+
+ /**
+ * Layout transform convenience property. Represents the rotation around the Z axis of the layout matrix used in layout and in
+ * the computed transform.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set layoutRotationZ(value:Number):void;
+
+ /**
+ * @private
+ */
+ function get layoutRotationZ():Number;
+
+ //------------------------------------------------------------------------------
+
+ /**
+ * Layout transform convenience property. Represents the scale along the X axis of the layout matrix used in layout and in
+ * the computed transform.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set layoutScaleX(value:Number):void;
+
+ /**
+ * @private
+ */
+ function get layoutScaleX():Number;
+
+ /**
+ * Layout transform convenience property. Represents the scale along the Y axis of the layout matrix used in layout and in
+ * the computed transform.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set layoutScaleY(value:Number):void;
+
+ /**
+ * @private
+ */
+ function get layoutScaleY():Number;
+
+ /**
+ * Layout transform convenience property. Represents the scale along the Z axis of the layout matrix used in layout and in
+ * the computed transform.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set layoutScaleZ(value:Number):void;
+
+ /**
+ * @private
+ */
+ function get layoutScaleZ():Number;
+
+ /**
+ * The 2D matrix used during layout calculations to determine the layout and size of the component and its parent and siblings.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set layoutMatrix(value:Matrix):void;
+
+ /**
+ * @private
+ */
+ function get layoutMatrix():Matrix;
+
+ /**
+ * The 3D matrix used during layout calculations to determine the layout and size of the component and its parent and siblings.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function set layoutMatrix3D(value:Matrix3D):void;
+
+ /**
+ * @private
+ */
+ function get layoutMatrix3D():Matrix3D;
+
+ /**
+ * True if the computed transform has 3D values.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function get is3D():Boolean;
+
+ /**
+ * True if the layout transform has 3D values.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function get layoutIs3D():Boolean;
+
+ /**
+ * If true the X axis is scaled by -1 and the x coordinate of the origin
+ * is translated by the component's width.
+ *
+ * The net effect of this "mirror" transform is to flip the direction
+ * that the X axis increases in without changing the layout element's
+ * location relative to the parent's origin.
+ *
+ * @default false
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function get mirror():Boolean;
+
+ /**
+ * @private
+ */
+ function set mirror(value:Boolean):void;
+
+
+ /**
+ * The stretchY is the horizontal component of the stretch scale factor which
+ * is applied before any other transformation property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function get stretchX():Number;
+
+ /**
+ * @private
+ */
+ function set stretchX(value:Number):void;
+
+ /**
+ * The stretchY is the vertical component of the stretch scale factor which
+ * is applied before any other transformation property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function get stretchY():Number;
+
+ /**
+ * @private
+ */
+ function set stretchY(value:Number):void;
+
+ //------------------------------------------------------------------------------
+
+ /**
+ * The computed matrix, calculated by combining the layout matrix and any offsets provided.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function get computedMatrix():Matrix;
+
+ /**
+ * The computed 3D matrix, calculated by combining the 3D layout matrix and any offsets provided.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function get computedMatrix3D():Matrix3D;
+}
+}
diff --git a/src/mx/core/IBorder.as b/src/mx/core/IBorder.as
new file mode 100644
index 00000000..2eb9e27a
--- /dev/null
+++ b/src/mx/core/IBorder.as
@@ -0,0 +1,62 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+/**
+ * The IBorder interface defines the interface that all classes
+ * used for border skins should implement.
+ *
+ * It is not an error if the border skin does not implement IBorder.
+ * In this case, however, the container using the skin cannot determine
+ * the border metrics of the border.
+ * Therefore, the container places content starting at its top-left edge
+ * (adjusted for padding, if any).
+ * For the HaloBorder class, the borderThickness style
+ * usually determines the value of the borderMetrics style.
+ * For graphical skin classes, Flex examines the scale9Grid
+ * property to determine the value of the borderMetrics style.
left, top, right,
+ * and bottom.
+ * The value of each property is equal to the thickness of one side
+ * of the border, in pixels.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get borderMetrics():EdgeMetrics;
+
+}
+
+}
diff --git a/src/mx/core/IDataRenderer.as b/src/mx/core/IDataRenderer.as
new file mode 100644
index 00000000..fb60b279
--- /dev/null
+++ b/src/mx/core/IDataRenderer.as
@@ -0,0 +1,95 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+/**
+ * The IDataRenderer interface defines the interface for components that have a data property.
+ *
+ * Components that are used in an item renderer or item editor
+ * in a list control (such as the List, HorizontalList, TileList, DataGrid,
+ * and Tree controls), or as renderers in a chart are passed the data
+ * to render or edit by using the data property.
+ * The component must implement IDataRenderer so that the host components
+ * can pass this information.
+ * All Flex containers and many Flex components implement IDataRenderer and
+ * the data property.
In a list control, Flex sets the data property
+ * of an item renderer or item editor to the element in the data provider
+ * that corresponds to the item being rendered or edited.
+ * For a DataGrid control, the data property
+ * contains the data provider element for the entire row of the DataGrid
+ * control, not just for the item.
To implement this interface, you define a setter and getter method
+ * to implement the data property.
+ * Typically, the setter method writes the value of the data
+ * property to an internal variable and dispatches a dataChange
+ * event, and the getter method returns the current value of the internal
+ * variable, as the following example shows:
+ * // Internal variable for the property value.
+ * private var _data:Object;
+ *
+ * // Make the data property bindable.
+ * [Bindable("dataChange")]
+ *
+ * // Define the getter method.
+ * public function get data():Object {
+ * return _data;
+ * }
+ *
+ * // Define the setter method, and dispatch an event when the property
+ * // changes to support data binding.
+ * public function set data(value:Object):void {
+ * _data = value;
+ *
+ * dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
+ * }
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public interface IDataRenderer
+{
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // data
+ //----------------------------------
+
+ /**
+ * The data to render or edit.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get data():Object;
+
+ /**
+ * @private
+ */
+ function set data(value:Object):void;
+}
+
+}
diff --git a/src/mx/core/IDeferredInstance.as b/src/mx/core/IDeferredInstance.as
new file mode 100644
index 00000000..c9500bee
--- /dev/null
+++ b/src/mx/core/IDeferredInstance.as
@@ -0,0 +1,98 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+/**
+ * The IDeferredInstance interface defines the Flex deferred instance factory interface.
+ * An implementation of IDeferredInstance creates a particular instance value
+ * when the getInstance() method is first called, and returns a reference to that value
+ * when the getInstance() method is called subsequently.
+ *
+ * The Flex compiler performs the following automatic coercions when it + * encounters MXML that assigns a value to a property with the + * IDeferredInstance type:
+ * + *getInstance() method returns an instance
+ * of the class, configured as specified in the MXML code.
+ * The following example shows this format; in this example,
+ * MyComp is a custom component that has a variable called
+ * myDeferredInstanceProperty of type IDeferredInstance. The compiler
+ * generates an IDeferredInstance1 implementation whose
+ * getInstance() method returns an instance of the
+ * Label class, with its text property set to
+ * "This is a deferred label":
+ * + * <MyComp> + * <myDeferredInstanceProperty> + * <Label text="This is a deferred label"/> + * </myDeferredInstanceProperty> + * </MyComp>+ *
getInstance()
+ * method returns a new instance of the specified class.
+ * The specified class must have a constructor with no arguments.
+ * The following example shows this format; in this example, the compiler
+ * generates an IDeferredInstance1 implementation whose
+ * getInstance() method returns an instance of the
+ * MyClass class:
+ * + * <MyComp myDeferredInstanceProperty="myPackage.MyClass/>+ *
Use the IDeferredInstance interface when an ActionScript class defers + * the instantiation of a property value. + * You cannot use IDeferredInstance if an ActionScript class requires + * multiple instances of the same value. + * In those situations, use the IFactory interface.
+ * + *The states.AddChild class includes a childFactory
+ * property that is of type IDeferredInstance.
For example, a DataGridColumn has an itemRenderer of type
+ * IFactory; it calls itemRenderer.newInstance() to create
+ * the cells for a particular column of the DataGrid.
The player uses ActionScript classes to represent + * embedded assets as well as executable ActionScript code. + * When you embed an asset in a Flex application, the MXML compiler + * autogenerates a class to represent it, and all such classes + * declare that they implement IFlexAsset so that they can be + * distinguished from the code classes.
+ * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public interface IFlexAsset +{ +} + +} diff --git a/src/mx/core/IFlexDisplayObject.as b/src/mx/core/IFlexDisplayObject.as new file mode 100644 index 00000000..9decfe1d --- /dev/null +++ b/src/mx/core/IFlexDisplayObject.as @@ -0,0 +1,142 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2005-2007 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.core +{ + +import flash.accessibility.AccessibilityProperties; +import flash.display.DisplayObject; +import flash.display.DisplayObjectContainer; +import flash.display.IBitmapDrawable; +import flash.display.LoaderInfo; +import flash.display.Stage; +import flash.events.IEventDispatcher; +import flash.geom.Rectangle; +import flash.geom.Point; +import flash.geom.Transform; + +/** + * The IFlexDisplayObject interface defines the interface for skin elements. + * At a minimum, a skin must be a DisplayObject and implement this interface. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public interface IFlexDisplayObject extends IBitmapDrawable, IEventDispatcher +{ + +include "IDisplayObjectInterface.as" + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + + //---------------------------------- + // measuredHeight + //---------------------------------- + + /** + * The measured height of this object. + * + *This is typically hard-coded for graphical skins
+ * because this number is simply the number of pixels in the graphic.
+ * For code skins, it can also be hard-coded
+ * if you expect to be drawn at a certain size.
+ * If your size can change based on properties, you may want
+ * to also be an ILayoutManagerClient so a measure()
+ * method will be called at an appropriate time,
+ * giving you an opportunity to compute a measuredHeight.
This is typically hard-coded for graphical skins
+ * because this number is simply the number of pixels in the graphic.
+ * For code skins, it can also be hard-coded
+ * if you expect to be drawn at a certain size.
+ * If your size can change based on properties, you may want
+ * to also be an ILayoutManagerClient so a measure()
+ * method will be called at an appropriate time,
+ * giving you an opportunity to compute a measuredHeight.
This method is mainly for use in implementing the
+ * updateDisplayList() method, which is where
+ * you compute this object's actual size based on
+ * its explicit size, parent-relative (percent) size,
+ * and measured size.
+ * You then apply this actual size to the object
+ * by calling setActualSize().
In other situations, you should be setting properties
+ * such as width, height,
+ * percentWidth, or percentHeight
+ * rather than calling this method.
Calling the info() method is legal immediately after
+ * the complete event is dispatched.
A well-behaved module dispatches a ready event when
+ * it is safe to call the create() method.
allowDomain()
+ * are also allowed by RSLs loaded after the call. Additional RSLs
+ * may be loaded into this module factory by sub-applications or modules.
+ *
+ * @default true
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.6
+ * @productversion Flex 4.5
+ */
+ function get allowDomainsInNewRSLs():Boolean;
+ function set allowDomainsInNewRSLs(value:Boolean):void;
+
+ /**
+ * Controls whether the domains allowed by calls to allowInsecureDomain()
+ * are also allowed by RSLs loaded after the call. Additional RSLs
+ * may be added to this module factory by sub-applications or modules.
+ *
+ * @default true
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.6
+ * @productversion Flex 4.5
+ */
+ function get allowInsecureDomainsInNewRSLs():Boolean;
+ function set allowInsecureDomainsInNewRSLs(value:Boolean):void;
+
+ /**
+ * The RSLs loaded by this SystemManager or FlexModuleFactory before the
+ * application starts. This dictionary may also include RSLs loaded into this
+ * module factory's application domain by other modules or
+ * sub-applications. When a new dictionary entry is added by a child module
+ * factory an RSLEvent.RSL_ADD_PRELOADED event is dispatched
+ * by module factory owning the dictionary.
+ *
+ * Information about preloadedRSLs is stored in a Dictionary. The key is
+ * the RSL's LoaderInfo. The value is the a Vector of RSLData where the
+ * first element is the primary RSL and the remaining elements are
+ * failover RSLs.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 3
+ */
+ function get preloadedRSLs():Dictionary;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Adds an RSL to the preloadedRSLs list. This method is called by child
+ * module factories when they add load an RSL into this module factory's
+ * application domain.
+ *
+ * You do not call this method directly. This method is called by child + * module factories when they add load an RSL into this module factory's + * application domain.
+ * + * @param loaderInfo The loaderInfo of the loaded RSL. + * @param rsl The RSL's configuration information. A Vector of RSLData. + * The first element in the array is the primary RSL. The remaining + * elements are failover RSLs. + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Flex 4.5 + */ + function addPreloadedRSL(loaderInfo:LoaderInfo, rsl:Vector.Security.allowDomain() method for the SWF
+ * associated with this IFlexModuleFactory plus all the SWFs associated
+ * with RSLs preloaded by this IFlexModuleFactory. RSLs loaded after this
+ * call will, by default, allow the same domains as have been allowed by
+ * previous calls to this method. This behavior is controlled by the
+ * allowDomainsInNewRSLs property.
+ *
+ * @param domains One or more strings or URLRequest objects that name
+ * the domains from which you want to allow access.
+ * You can specify the special domain "*" to allow access from all domains.
+ *
+ * @see flash.system.Security#allowDomain()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.6
+ * @productversion Flex 4.5
+ */
+ function allowDomain(... domains):void;
+
+ /**
+ * Calls the Security.allowInsecureDomain() method for the
+ * SWF associated with this IFlexModuleFactory
+ * plus all the SWFs associated with RSLs preloaded by this
+ * IFlexModuleFactory. RSLs loaded after this call will, by default,
+ * allow the same domains as have been allowed by
+ * previous calls to this method. This behavior is controlled by the
+ * allowInsecureDomainsInNewRSLs property.
+ *
+ * @param domains One or more strings or URLRequest objects that name
+ * the domains from which you want to allow access.
+ * You can specify the special domain "*" to allow access from all domains.
+ *
+ * @see flash.system.Security#allowInsecureDomain()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.6
+ * @productversion Flex 4.5
+ */
+ function allowInsecureDomain(... domains):void;
+
+ /**
+ * A way to call a method in this IFlexModuleFactory's context
+ *
+ * @param fn The function or method to call.
+ * @param thisArg The this pointer for the function.
+ * @param argArray The arguments for the function.
+ * @param returns If true, the function returns a value.
+ *
+ * @return Whatever the function returns, if anything.
+ *
+ * @see Function.apply
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 3
+ */
+ function callInContext(fn:Function, thisArg:Object,
+ argArray:Array, returns:Boolean = true):*;
+
+ /**
+ * A factory method that requests
+ * an instance of a definition known to the module.
+ *
+ * You can provide an optional set of parameters to let
+ * building factories change what they create based
+ * on the input.
+ * Passing null indicates that the default
+ * definition is created, if possible.
parameters.
+ *
+ * @return An instance of the module, or null.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function create(... parameters):Object;
+
+ /**
+ * Get the implementation for an interface.
+ * Similar to Singleton.getInstance() method, but per-
+ * IFlexModuleFactory.
+ *
+ * @param interfaceName The interface.
+ *
+ * @return The implementation for the interface.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function getImplementation(interfaceName:String):Object;
+
+ /**
+ * Returns a block of key/value pairs
+ * that hold static data known to the module.
+ * This method always succeeds, but can return an empty object.
+ *
+ * @return An object containing key/value pairs. Typically, this object
+ * contains information about the module or modules created by this
+ * factory; for example:
+ *
+ *
+ * return {"description": "This module returns 42."};
+ *
+ *
+ * Other common values in the returned object include the following:
+ * fonts: A list of embedded font faces.rsls: A list of run-time shared libraries.mixins: A list of classes initialized at startup.Singleton.registerClass() method, but per-
+ * IFlexModuleFactory, and takes an instance not a class.
+ *
+ * @param interfaceName The interface.
+ *
+ * @param impl The implementation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function registerImplementation(interfaceName:String,
+ impl:Object):void;
+
+}
+
+}
diff --git a/src/mx/core/ILayoutDirectionElement.as b/src/mx/core/ILayoutDirectionElement.as
new file mode 100644
index 00000000..56488517
--- /dev/null
+++ b/src/mx/core/ILayoutDirectionElement.as
@@ -0,0 +1,74 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2003-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+package mx.core
+{
+
+ /**
+ * The ILayoutDirectionElement interface defines the minimum properties and methods
+ * required for an Object to support the layoutDirection property.
+ *
+ * @see mx.core.LayoutDirection
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ public interface ILayoutDirectionElement
+ {
+
+ /**
+ * Specifies the desired layout direction for an element: one of LayoutDirection.LTR
+ * (left to right), LayoutDirection.RTL (right to left), or null (inherit).
+ *
+ * This property is typically backed by an inheriting style. If null,
+ * the layoutDirection style will be set to undefined.
+ *
+ * Classes like GraphicElement, which implement ILayoutDirectionElement but do not
+ * support styles, must additionally support a null value for this property
+ * which means the layoutDirection must be inherited from its parent.
+ *
+ * @see mx.core.LayoutDirection
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function get layoutDirection():String;
+
+ /**
+ * @private
+ */
+ function set layoutDirection(value:String):void;
+
+ /**
+ * An element must call this method when its layoutDirection changes or
+ * when its parent's layoutDirection changes.
+ *
+ * If they differ, this method is responsible for mirroring the element’s contents
+ * and for updating the element’s post-layout transform so that descendants inherit
+ * a mirrored coordinate system. IVisualElements typically implement
+ * mirroring by using postLayoutTransformOffsets to scale the X axis by -1 and
+ * to translate the x coordinate of the origin by the element's width.
+ *
+ * The net effect of this "mirror" transform is to reverse the direction
+ * in which the X axis increases without changing the element's location
+ * relative to its parent's origin.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ function invalidateLayoutDirection():void;
+ }
+}
diff --git a/src/mx/core/IMXMLObject.as b/src/mx/core/IMXMLObject.as
new file mode 100644
index 00000000..2ee7153e
--- /dev/null
+++ b/src/mx/core/IMXMLObject.as
@@ -0,0 +1,18 @@
+package mx.core
+{
+ public interface IMXMLObject
+ {
+ /**
+ * Called after the implementing object has been created and all
+ * component properties specified on the MXML tag have been initialized.
+ *
+ * @param document The MXML document that created this object.
+ *
+ * @param id The identifier used by document to refer
+ * to this object.
+ * If the object is a deep property on document,
+ * id is null.
+ */
+ function initialized(document:Object, id:String):void;
+ }
+}
\ No newline at end of file
diff --git a/src/mx/core/IPropertyChangeNotifier.as b/src/mx/core/IPropertyChangeNotifier.as
new file mode 100644
index 00000000..77c55ec5
--- /dev/null
+++ b/src/mx/core/IPropertyChangeNotifier.as
@@ -0,0 +1,89 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+import flash.events.IEventDispatcher;
+
+/**
+ * The IPropertyChangeNotifier interface defines a marker
+ * interface.
+ * Classes that support this interface declare support for event propagation
+ * in a specialized manner.
+ * Classes that implement this interface must dispatch events for each property
+ * of this class and any nested classes publicly exposed as properties.
+ * For those properties that are anonymous (complex and not strongly typed),
+ * implementing classes provide custom support or directly use the
+ * ObjectProxy class.
+ * Implementors of this interface should use the
+ * PropertyChangeEvent.createUpdateEvent() method to construct an
+ * appropriate update event for dispatch.
+ * @example
+ *
+ *
+ * function set myProperty(value:Object):void
+ * {
+ * var oldValue:IPropertyChangeNotifier = _myProperty;
+ * var newValue:IPropertyChangeNotifier = value;
+ *
+ * // Need to ensure to dispatch changes on the new property.
+ * // Listeners use the source property to determine which object
+ * // actually originated the event.
+ * // In their event handler code, they can tell if an event has been
+ * // propagated from deep within the object graph by comparing
+ * // event.target and event.source. If they are equal, then the property
+ * // change is at the surface of the object. If they are not equal, the
+ * // property change is somewhere deeper in the object graph.
+ * newValue.addEventListener(
+ * PropertyChangeEvent.PROPERTY_CHANGE,
+ * dispatchEvent);
+ *
+ * // need to stop listening for events from the old property
+ * oldValue.removeEventListener(
+ * PropertyChangeEvent.PROPERTY_CHANGE,
+ * dispatchEvent);
+ *
+ * _myProperty = newValue;
+ *
+ * // now notify anyone that is listening
+ * if (dispatcher.hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE))
+ * {
+ * var event:PropertyChangeEvent =
+ * PropertyChangeEvent.createUpdateEvent(
+ * this,
+ * "myProperty",
+ * newValue,
+ * oldValue);
+ * dispatchEvent(event);
+ * }
+ * }
+ *
+ *
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public interface IPropertyChangeNotifier extends IEventDispatcher, IUID
+{
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ // Inherits uid property from IUID
+}
+
+}
diff --git a/src/mx/core/IStateClient.as b/src/mx/core/IStateClient.as
new file mode 100644
index 00000000..6ff0651d
--- /dev/null
+++ b/src/mx/core/IStateClient.as
@@ -0,0 +1,12 @@
+package mx.core
+{
+ public interface IStateClient
+ {
+ function get currentState():String;
+
+ /**
+ * @private
+ */
+ function set currentState(value:String):void;
+ }
+}
\ No newline at end of file
diff --git a/src/mx/core/IStateClient2.as b/src/mx/core/IStateClient2.as
new file mode 100644
index 00000000..12b66bcc
--- /dev/null
+++ b/src/mx/core/IStateClient2.as
@@ -0,0 +1,31 @@
+package mx.core
+{
+ import flash.events.IEventDispatcher;
+
+ public interface IStateClient2 extends IEventDispatcher, IStateClient
+ {
+
+ [ArrayElementType("mx.states.State")]
+ function get states():Array;
+
+ /**
+ * @private
+ */
+ function set states(value:Array):void;
+
+
+ //----------------------------------
+ // transitions
+ //----------------------------------
+
+ [ArrayElementType("mx.states.Transition")]
+ function get transitions():Array;
+
+ /**
+ * @private
+ */
+ function set transitions(value:Array):void;
+
+ function hasState(stateName:String):Boolean
+ }
+}
\ No newline at end of file
diff --git a/src/mx/core/ITransientDeferredInstance.as b/src/mx/core/ITransientDeferredInstance.as
new file mode 100644
index 00000000..3695c4aa
--- /dev/null
+++ b/src/mx/core/ITransientDeferredInstance.as
@@ -0,0 +1,57 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+/**
+ * The ITransientDeferredInstance interface extends IDeferredInstance and adds
+ * the ability for the user to reset the deferred instance factory to its
+ * initial state (usually this implies releasing any known references to the
+ * component, such as the setting the owning document property that refers to
+ * the instance to null).
+ *
+ * This additional capability is leveraged by the AddItems states override when
+ * the desired behavior is to destroy a state-specific element when a state
+ * no longer applies.
+ *
+ * The Flex compiler uses the same automatic coercion rules as with
+ * IDeferredInstance.
+ *
+ * @see mx.states.AddItems
+ * @see mx.core.IDeferredInstance
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public interface ITransientDeferredInstance extends IDeferredInstance
+{
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Resets the state of our factory to its initial state, clearing any
+ * references to the cached instance.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function reset():void;
+}
+
+}
diff --git a/src/mx/core/IUID.as b/src/mx/core/IUID.as
new file mode 100644
index 00000000..81696659
--- /dev/null
+++ b/src/mx/core/IUID.as
@@ -0,0 +1,54 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+/**
+ * The IUID interface defines the interface for objects that must have
+ * Unique Identifiers (UIDs) to uniquely identify the object.
+ * UIDs do not need to be universally unique for most uses in Flex.
+ * One exception is for messages send by data services.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public interface IUID
+{
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // uid
+ //----------------------------------
+
+ /**
+ * The unique identifier for this object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get uid():String;
+
+ /**
+ * @private
+ */
+ function set uid(value:String):void;
+}
+
+}
diff --git a/src/mx/core/RSLData.as b/src/mx/core/RSLData.as
new file mode 100644
index 00000000..b472da58
--- /dev/null
+++ b/src/mx/core/RSLData.as
@@ -0,0 +1,279 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2010 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+/**
+ * A Class that describes configuration data for an RSL.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+public class RSLData
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param rslURL The location of the RSL.
+ * @param policyFileURL The location of the policy file url (optional).
+ * @param digest The digest of the RSL. This is null for an RSL without
+ * a digest.
+ * @param hashType The type of hash used to create the digest. The only
+ * supported value is SHA256.TYPE_ID.
+ * @param isSigned True if the RSL has been signed by Adobe, false
+ * otherwise.
+ * @param verifyDigest Detemines if the RSL's digest should be verified
+ * after it is loaded.
+ * @param applicationDomainTarget The application domain where the the
+ * RSL should be loaded. For valid values see the ApplicationDomainTarget
+ * enumeration.
+ *
+ * @see mx.core.ApplicationDomainTarget
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+ public function RSLData(rslURL:String = null,
+ policyFileURL:String = null,
+ digest:String = null,
+ hashType:String = null,
+ isSigned:Boolean = false,
+ verifyDigest:Boolean = false,
+ applicationDomainTarget:String = "default")
+ {
+ super();
+
+ _rslURL = rslURL
+ _policyFileURL = policyFileURL;
+ _digest = digest;
+ _hashType = hashType;
+ _isSigned = isSigned;
+ _verifyDigest = verifyDigest;
+ _applicationDomainTarget = applicationDomainTarget;
+ _moduleFactory = moduleFactory;
+
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // applicationDomainTarget
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _applicationDomainTarget:String;
+
+ /**
+ * The requested application domain to load the RSL into.
+ * For valid values see the ApplicationDomainTarget enumeration.
+ *
+ * @see mx.core.ApplicationDomainTarget
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+ public function get applicationDomainTarget():String
+ {
+ return _applicationDomainTarget;
+ }
+
+ //----------------------------------
+ // digest
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _digest:String;
+
+ /**
+ * The digest of the RSL. This is null for an RSL without a digest.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+ public function get digest():String
+ {
+ return _digest;
+ }
+
+ //----------------------------------
+ // hash type
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _hashType:String;
+
+ /**
+ * The type of hash used to create the RSL digest. The only supported hash
+ * type is SHA256.TYPE_ID.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+ public function get hashType():String
+ {
+ return _hashType;
+ }
+
+ //----------------------------------
+ // isSigned
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _isSigned:Boolean;
+
+ /**
+ * True if the RSL has been signed by Adobe. False otherwise.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+ public function get isSigned():Boolean
+ {
+ return _isSigned;
+ }
+
+ //----------------------------------
+ // moduleFactory
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _moduleFactory:IFlexModuleFactory;
+
+ /**
+ * Non-null if this RSL should be loaded into an application
+ * domain other than the application domain associated with the
+ * module factory performing the load. If null, then load into
+ * the current application domain.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+ public function get moduleFactory():IFlexModuleFactory
+ {
+ return _moduleFactory;
+ }
+
+ /**
+ * @private
+ */
+ public function set moduleFactory(moduleFactory:IFlexModuleFactory):void
+ {
+ _moduleFactory = moduleFactory;
+ }
+
+ //----------------------------------
+ // policyFileURL
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _policyFileURL:String;
+
+ /**
+ * An URL that specifies the location of the policy file (optional).
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+ public function get policyFileURL():String
+ {
+ return _policyFileURL;
+ }
+
+ //----------------------------------
+ // rslURL
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _rslURL:String;
+
+ /**
+ * The location of the RSL. The URL can be absolute or relative to the
+ * application or module.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+ public function get rslURL():String
+ {
+ return _rslURL;
+ }
+
+ //----------------------------------
+ // verifyDigest
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _verifyDigest:Boolean;
+
+ /**
+ * True if the digest must be verified before loading the RSL into memory.
+ * False allows the RSL to be loaded without verification. Signed RSLs
+ * are always verified regardless of the value.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10.2
+ * @playerversion AIR 2.5
+ * @productversion Flex 4.5
+ */
+ public function get verifyDigest():Boolean
+ {
+ return _verifyDigest;
+ }
+
+}
+}
\ No newline at end of file
diff --git a/src/mx/core/Singleton.as b/src/mx/core/Singleton.as
new file mode 100644
index 00000000..964095cd
--- /dev/null
+++ b/src/mx/core/Singleton.as
@@ -0,0 +1,117 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+[ExcludeClass]
+
+/**
+ * @private
+ * This all-static class serves as a singleton registry.
+ *
+ * For example, pop-up management throughout a Flex application
+ * is provided by a single instance of the PopUpManagerImpl class,
+ * even when the main application loads modules and sub-applications
+ * each of which might have PopUpManagerImpl linked in.
+ *
+ * The factory class for a framework-based application
+ * or a module (i.e., SystemManager or FlexModuleFactory,
+ * both of which implements IFlexModuleFactory) calls
+ * the registerClass() method to populate the registry.
+ *
+ * Later, other classes call getInstance() to access
+ * the singleton instance.
+ *
+ * The registry policy is "first class in wins".
+ * For example, if the main application registers its
+ * PopUpManagerImpl, then a loaded SWF will use that one.
+ * However, if the main application doesn't contain
+ * a PopUpManagerImpl, then it registers null,
+ * and the first loaded SWF containing a PopUpManagerImpl
+ * will register that one.
+ */
+public class Singleton
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * A map of fully-qualified interface names,
+ * such as "mx.managers::IPopUpManager",
+ * to implementation classes which produce singleton instances,
+ * such as mx.managers.PopUpManagerImpl.
+ */
+ private static var classMap:Object = {};
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Adds an interface-name-to-implementation-class mapping to the registry,
+ * if a class hasn't already been registered for the specified interface.
+ * The class must implement a getInstance() method which returns
+ * its singleton instance.
+ */
+ public static function registerClass(interfaceName:String,
+ clazz:Class):void
+ {
+ var c:Class = classMap[interfaceName];
+ if (!c)
+ classMap[interfaceName] = clazz;
+ }
+
+ /**
+ * @private
+ * Returns the implementation class registered for the specified
+ * interface, or null if no class has been registered for that interface.
+ *
+ * This method should not be called at static initialization time,
+ * because the factory class may not have called registerClass() yet.
+ */
+ public static function getClass(interfaceName:String):Class
+ {
+ return classMap[interfaceName];
+ }
+
+ /**
+ * @private
+ * Returns the singleton instance of the implementation class
+ * that was registered for the specified interface,
+ * by looking up the class in the registry
+ * and calling its getInstance() method.
+ *
+ * This method should not be called at static initialization time,
+ * because the factory class may not have called registerClass() yet.
+ */
+ public static function getInstance(interfaceName:String):Object
+ {
+ var c:Class = classMap[interfaceName];
+ if (!c)
+ {
+ throw new Error("No class registered for interface '" +
+ interfaceName + "'.");
+ }
+ return c["getInstance"]();
+ }
+}
+
+}
diff --git a/src/mx/core/SpriteAsset.as b/src/mx/core/SpriteAsset.as
new file mode 100644
index 00000000..c6d26bbe
--- /dev/null
+++ b/src/mx/core/SpriteAsset.as
@@ -0,0 +1,808 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+import flash.display.DisplayObjectContainer;
+import flash.events.Event;
+import flash.geom.Point;
+import flash.system.ApplicationDomain;
+
+/**
+ * SpriteAsset is a subclass of the flash.display.Sprite class which
+ * represents vector graphic images that you embed in an application.
+ * It implements the IFlexDisplayObject interface, which makes it
+ * possible for an embedded vector graphic image to be displayed in an Image
+ * control, or to be used as a container background or a component skin.
+ *
+ * The vector graphic image that you're embedding can be in an SVG file. + * You can also embed a sprite symbol that is in a SWF file produced + * by Flash. + * In both cases, the MXML compiler autogenerates a class that extends + * SpriteAsset to represent the embedded vector graphic image.
+ * + *You don't generally have to use the SpriteAsset class directly + * when you write a Flex application. + * For example, you can embed a sprite symbol from a SWF file and display + * it in an Image control by writing the following:
+ * + *+ * <mx:Image id="logo" source="@Embed(source='Assets.swf', symbol='Logo')"/>+ * + *
Or use it as the application's background image in CSS syntax + * by writing the following:
+ * + *
+ * <fx:Style>
+ * @namespace mx "library://ns.adobe.com/flex/mx"
+ * mx|Application {
+ * backgroundImage: Embed(source="Assets.swf", symbol='Logo')
+ * }
+ * <fx:Style/>
+ *
+ * without having to understand that the MXML compiler has created + * a subclass of BitmapAsset for you.
+ * + *However, it may be useful to understand what is happening
+ * at the ActionScript level.
+ * To embed a vector graphic image in ActionScript, you declare a variable
+ * of type Class, and put [Embed] metadata on it.
+ * For example, you embed a sprite symbol from a SWF file like this:
+ * [Bindable] + * [Embed(source="Assets.swf", symbol="Logo")] + * private var logoClass:Class;+ * + *
The MXML compiler notices that the Logo symbol in Assets.swf
+ * is a sprite, autogenerates a subclass of the SpriteAsset class
+ * to represent it, and sets your variable to be a reference to this
+ * autogenerated class.
+ * You can then use this class reference to create instances of the
+ * SpriteAsset using the new operator, and use APIs
+ * of the Sprite class on them:
+ * var logo:SpriteAsset = SpriteAsset(new logoClass()); + * logo.rotation=45;+ * + *
However, you rarely need to create SpriteAsset instances yourself
+ * because image-related properties and styles can simply be set to an
+ * image-producing class, and components will create image instances
+ * as necessary.
+ * For example, to display this vector graphic image in an Image control,
+ * you can set the Image's source property to
+ * logoClass.
+ * In MXML you could do this as follows:
+ * <mx:Image id="logo" source="{logoClass}"/>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class SpriteAsset extends FlexSprite
+ implements IFlexAsset, IFlexDisplayObject, IBorder,
+ ILayoutDirectionElement
+{
+ include "../core/Version.as";
+
+ // Softlink FlexVersion and MatrixUtil to remove dependencies of embeds on
+ // framework classes. This helps to reduce swf size in AS-only projects.
+ private static var FlexVersionClass:Class;
+ private static var MatrixUtilClass:Class;
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function SpriteAsset()
+ {
+ super();
+
+ // Remember initial size as our measured size.
+ _measuredWidth = width;
+ _measuredHeight = height;
+
+ if (FlexVersionClass == null)
+ {
+ var appDomain:ApplicationDomain = ApplicationDomain.currentDomain;
+ if (appDomain.hasDefinition("mx.core::FlexVersion"))
+ FlexVersionClass = Class(appDomain.getDefinition("mx.core::FlexVersion"));
+ }
+
+ if (FlexVersionClass && FlexVersionClass["compatibilityVersion"] >= FlexVersionClass["VERSION_4_0"])
+ this.addEventListener(Event.ADDED, addedHandler);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ // Softlink AdvancedLayoutFeatures to remove dependencies of embeds on
+ // framework classes. This helps to reduce swf size in AS-only projects.
+ private var layoutFeaturesClass:Class;
+ private var layoutFeatures:IAssetLayoutFeatures;
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // x
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get x():Number
+ {
+ // TODO(hmuller): by default get x returns transform.matrix.tx rounded to the nearest 20th.
+ // should do the same here, if we're returning layoutFeatures.layoutX.
+ return (layoutFeatures == null) ? super.x : layoutFeatures.layoutX;
+ }
+
+ /**
+ * @private
+ */
+ override public function set x(value:Number):void
+ {
+ if (x == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.x = value;
+ }
+ else
+ {
+ layoutFeatures.layoutX = value;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // y
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get y():Number
+ {
+ return (layoutFeatures == null) ? super.y : layoutFeatures.layoutY;
+ }
+
+ /**
+ * @private
+ */
+ override public function set y(value:Number):void
+ {
+ if (y == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.y = value;
+ }
+ else
+ {
+ layoutFeatures.layoutY = value;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // z
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get z():Number
+ {
+ return (layoutFeatures == null) ? super.z : layoutFeatures.layoutZ;
+ }
+
+ /**
+ * @private
+ */
+ override public function set z(value:Number):void
+ {
+ if (z == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.z = value;
+ }
+ else
+ {
+ layoutFeatures.layoutZ = value;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // width
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get width():Number
+ {
+ if (layoutFeatures == null)
+ return super.width;
+
+ // Return bounding box width in mirroring case
+ var p:Point;
+ if (MatrixUtilClass != null)
+ p = MatrixUtilClass["transformSize"](layoutFeatures.layoutWidth, _height, transform.matrix);
+
+ return p ? p.x : super.width;
+ }
+
+ /**
+ * @private
+ */
+ override public function set width(value:Number):void
+ {
+ if (width == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.width = value;
+ }
+ else
+ {
+ layoutFeatures.layoutWidth = value;
+ // Calculate scaleX based on initial width. We set scaleX
+ // here because resizing a BitmapAsset normally would adjust
+ // the scale to match.
+ layoutFeatures.layoutScaleX = measuredWidth != 0 ? value / measuredWidth : 0;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // height
+ //----------------------------------
+
+ private var _height:Number;
+
+ /**
+ * @private
+ */
+ override public function get height():Number
+ {
+
+ if (layoutFeatures == null)
+ return super.height;
+
+ // Return bounding box height in mirroring case
+ var p:Point;
+ if (MatrixUtilClass != null)
+ p = MatrixUtilClass["transformSize"](layoutFeatures.layoutWidth, _height, transform.matrix);
+
+ return p ? p.y : super.height;
+ }
+
+ /**
+ * @private
+ */
+ override public function set height(value:Number):void
+ {
+ if (height == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.height = value;
+ }
+ else
+ {
+ _height = value;
+ // Calculate scaleY based on initial height. We set scaleY
+ // here because resizing a BitmapAsset normally would adjust
+ // the scale to match.
+ layoutFeatures.layoutScaleY = measuredHeight != 0 ? value / measuredHeight : 0;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // rotation
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get rotationX():Number
+ {
+ return (layoutFeatures == null) ? super.rotationX : layoutFeatures.layoutRotationX;
+ }
+
+ /**
+ * @private
+ */
+ override public function set rotationX(value:Number):void
+ {
+ if (rotationX == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.rotationX = value;
+ }
+ else
+ {
+ layoutFeatures.layoutRotationX = value;
+ validateTransformMatrix();
+ }
+ }
+ /**
+ * @private
+ */
+ override public function get rotationY():Number
+ {
+ return (layoutFeatures == null) ? super.rotationY : layoutFeatures.layoutRotationY;
+ }
+
+ /**
+ * @private
+ */
+ override public function set rotationY(value:Number):void
+ {
+ if (rotationY == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.rotationY = value;
+ }
+ else
+ {
+ layoutFeatures.layoutRotationY = value;
+ validateTransformMatrix();
+ }
+ }
+
+ /**
+ * @private
+ */
+ override public function get rotationZ():Number
+ {
+ return (layoutFeatures == null) ? super.rotationZ : layoutFeatures.layoutRotationZ;
+ }
+
+ /**
+ * @private
+ */
+ override public function set rotationZ(value:Number):void
+ {
+ if (rotationZ == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.rotationZ = value;
+ }
+ else
+ {
+ layoutFeatures.layoutRotationZ = value;
+ validateTransformMatrix();
+ }
+ }
+
+ /**
+ * @private
+ */
+ override public function get rotation():Number
+ {
+ return (layoutFeatures == null) ? super.rotation : layoutFeatures.layoutRotationZ;
+ }
+
+ /**
+ * @private
+ */
+ override public function set rotation(value:Number):void
+ {
+ // TODO (klin): rotation actually affects width and height as well.
+ if (rotation == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.rotation = value;
+ }
+ else
+ {
+ layoutFeatures.layoutRotationZ = value;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // scaleX
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get scaleX():Number
+ {
+ return (layoutFeatures == null) ? super.scaleX : layoutFeatures.layoutScaleX;
+ }
+
+ /**
+ * @private
+ */
+ override public function set scaleX(value:Number):void
+ {
+ if (scaleX == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.scaleX = value;
+ }
+ else
+ {
+ layoutFeatures.layoutScaleX = value;
+ layoutFeatures.layoutWidth = Math.abs(value) * measuredWidth;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // scaleY
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get scaleY():Number
+ {
+ return (layoutFeatures == null) ? super.scaleY : layoutFeatures.layoutScaleY;
+ }
+
+ /**
+ * @private
+ */
+ override public function set scaleY(value:Number):void
+ {
+ if (scaleY == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.scaleY = value;
+ }
+ else
+ {
+ layoutFeatures.layoutScaleY = value;
+ _height = Math.abs(value) * measuredHeight;
+ validateTransformMatrix();
+ }
+ }
+
+ //----------------------------------
+ // scaleZ
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function get scaleZ():Number
+ {
+ return (layoutFeatures == null) ? super.scaleZ : layoutFeatures.layoutScaleZ;
+ }
+
+ /**
+ * @private
+ */
+ override public function set scaleZ(value:Number):void
+ {
+ if (scaleZ == value)
+ return;
+
+ if (layoutFeatures == null)
+ {
+ super.scaleZ = value;
+ }
+ else
+ {
+ layoutFeatures.layoutScaleZ = value;
+ validateTransformMatrix();
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // layoutDirection
+ //----------------------------------
+
+ // Use "ltr" instead of LayoutDirection.LTR to avoid depending
+ // on that framework class.
+ private var _layoutDirection:String = "ltr";
+
+ [Inspectable(category="General", enumeration="ltr,rtl")]
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ public function get layoutDirection():String
+ {
+ return _layoutDirection;
+ }
+
+ public function set layoutDirection(value:String):void
+ {
+ if (value == _layoutDirection)
+ return;
+
+ _layoutDirection = value;
+ invalidateLayoutDirection();
+ }
+
+ //----------------------------------
+ // measuredHeight
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the measuredHeight property.
+ */
+ private var _measuredHeight:Number;
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get measuredHeight():Number
+ {
+ return _measuredHeight;
+ }
+
+ //----------------------------------
+ // measuredWidth
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the measuredWidth property.
+ */
+ private var _measuredWidth:Number;
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get measuredWidth():Number
+ {
+ return _measuredWidth;
+ }
+
+ //----------------------------------
+ // borderMetrics
+ //----------------------------------
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get borderMetrics():EdgeMetrics
+ {
+ if (scale9Grid == null)
+ {
+ return EdgeMetrics.EMPTY;
+ }
+ else
+ {
+ return new EdgeMetrics(scale9Grid.left,
+ scale9Grid.top,
+ Math.ceil(measuredWidth - scale9Grid.right),
+ Math.ceil(measuredHeight - scale9Grid.bottom));
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ public function invalidateLayoutDirection():void
+ {
+ var p:DisplayObjectContainer = parent;
+
+ // We check the closest parent's layoutDirection property
+ // to create or destroy layoutFeatures if needed.
+ while (p)
+ {
+ if (p is ILayoutDirectionElement)
+ {
+ // mirror is true if our layoutDirection differs from our parent's.
+ var mirror:Boolean = _layoutDirection != null &&
+ ILayoutDirectionElement(p).layoutDirection != null &&
+ (_layoutDirection != ILayoutDirectionElement(p).layoutDirection);
+
+ // If our layoutDirection is different from our parent's and if it used to
+ // be the same, create layoutFeatures to handle mirroring.
+ if (mirror && layoutFeatures == null)
+ {
+ initAdvancedLayoutFeatures();
+ if (layoutFeatures != null)
+ {
+ layoutFeatures.mirror = mirror;
+ validateTransformMatrix();
+ }
+ }
+ else if (!mirror && layoutFeatures)
+ {
+ // If our layoutDirection is not different from our parent's and if
+ // it used to be different, then recover our matrix and remove layoutFeatures.
+ layoutFeatures.mirror = mirror;
+ validateTransformMatrix();
+ layoutFeatures = null;
+ }
+
+ break;
+ }
+
+ p = p.parent;
+ }
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function move(x:Number, y:Number):void
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function setActualSize(newWidth:Number, newHeight:Number):void
+ {
+ width = newWidth;
+ height = newHeight;
+ }
+
+ /**
+ * @private
+ */
+ private function addedHandler(event:Event):void
+ {
+ invalidateLayoutDirection();
+ }
+
+ /**
+ * @private
+ * Initializes AdvancedLayoutFeatures for this asset when mirroring.
+ */
+ private function initAdvancedLayoutFeatures():void
+ {
+ // Get AdvancedLayoutFeatures if it exists.
+ if (layoutFeaturesClass == null)
+ {
+ var appDomain:ApplicationDomain = ApplicationDomain.currentDomain;
+
+ if (appDomain.hasDefinition("mx.core::AdvancedLayoutFeatures"))
+ layoutFeaturesClass = Class(appDomain.getDefinition("mx.core::AdvancedLayoutFeatures"));
+
+ // Get MatrixUtil class if it exists
+ if (MatrixUtilClass == null)
+ {
+ if (appDomain.hasDefinition("mx.utils::MatrixUtil"))
+ MatrixUtilClass = Class(appDomain.getDefinition("mx.utils::MatrixUtil"));
+ }
+ }
+
+ if (layoutFeaturesClass != null)
+ {
+ var features:IAssetLayoutFeatures = new layoutFeaturesClass();
+
+ features.layoutScaleX = scaleX;
+ features.layoutScaleY = scaleY;
+ features.layoutScaleZ = scaleZ;
+ features.layoutRotationX = rotationX;
+ features.layoutRotationY = rotationY;
+ features.layoutRotationZ = rotation;
+ features.layoutX = x;
+ features.layoutY = y;
+ features.layoutZ = z;
+ features.layoutWidth = width; // for the mirror transform
+ _height = height; // for backing storage
+ layoutFeatures = features;
+ }
+ }
+
+ /**
+ * @private
+ * Applies the transform matrix calculated by AdvancedLayoutFeatures
+ * so that this bitmap will not be mirrored if a parent is mirrored.
+ */
+ private function validateTransformMatrix():void
+ {
+ if (layoutFeatures != null)
+ {
+ if (layoutFeatures.is3D)
+ super.transform.matrix3D = layoutFeatures.computedMatrix3D;
+ else
+ super.transform.matrix = layoutFeatures.computedMatrix;
+ }
+ }
+}
+
+}
diff --git a/src/mx/core/TextFieldFactory.as b/src/mx/core/TextFieldFactory.as
new file mode 100644
index 00000000..35fb4197
--- /dev/null
+++ b/src/mx/core/TextFieldFactory.as
@@ -0,0 +1,193 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+import flash.text.TextField;
+import flash.utils.Dictionary;
+
+use namespace mx_internal;
+
+[ExcludeClass]
+
+/**
+ * @private
+ * Singleton to create TextFields in the context of various ModuleFactories.
+ * One module factory will have at most one TextField created for it.
+ * The text fields are only used for measurement;
+ * they are not on the display list.
+ */
+public class TextFieldFactory implements ITextFieldFactory
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ *
+ * This classes singleton.
+ */
+ private static var instance:ITextFieldFactory;
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ public static function getInstance():ITextFieldFactory
+ {
+ if (!instance)
+ instance = new TextFieldFactory();
+
+ return instance;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Cache of TextFields. Limit of one per module factory.
+ * In this Dictionary, each key is a weak reference
+ * to an IFlexModuleFactory and each value is a Dictionary
+ * with a single entry (a TextField as a weak key).
+ */
+ private var textFields:Dictionary = new Dictionary(true);
+
+ /**
+ * @private
+ * Cache of FTETextFields. Limit of one per module factory.
+ * In this Dictionary, each key is a weak reference
+ * to an IFlexModuleFactory and each value is a Dictionary
+ * with a single entry (a FTETextField as a weak key).
+ */
+ private var fteTextFields:Dictionary = new Dictionary(true);
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Creates an instance of TextField
+ * in the context of the specified IFlexModuleFactory.
+ *
+ * @param moduleFactory The IFlexModuleFactory requesting the TextField.
+ *
+ * @return A FTETextField created in the context
+ * of moduleFactory.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function createTextField(moduleFactory:IFlexModuleFactory):TextField
+ {
+ // Check to see if we already have a text field for this module factory.
+ var textField:TextField = null;
+ var textFieldDictionary:Dictionary = textFields[moduleFactory];
+
+ if (textFieldDictionary)
+ {
+ for (var iter:Object in textFieldDictionary)
+ {
+ textField = TextField(iter);
+ break;
+ }
+ }
+ if (!textField)
+ {
+ if (moduleFactory)
+ textField = TextField(moduleFactory.create("flash.text.TextField"));
+ else
+ textField = new TextField();
+
+ // The dictionary could be empty, but not null because entries in the dictionary
+ // could be garbage collected.
+ if (!textFieldDictionary)
+ textFieldDictionary = new Dictionary(true);
+ textFieldDictionary[textField] = 1;
+ textFields[moduleFactory] = textFieldDictionary;
+ }
+
+ return textField;
+ }
+
+ /**
+ * @private
+ * Creates an instance of FTETextField
+ * in the context of the specified module factory.
+ *
+ * @param moduleFactory The IFlexModuleFactory requesting the TextField.
+ * May not be null.
+ *
+ * @return A FTETextField created in the context
+ * of moduleFactory.
+ * The return value is loosely typed as Object
+ * to avoid linking in FTETextField (and therefore much of TLF).
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 4
+ */
+ public function createFTETextField(moduleFactory:IFlexModuleFactory):Object
+ {
+ // Check to see if we already have a text field for this module factory.
+ var fteTextField:Object = null;
+ var fteTextFieldDictionary:Dictionary = fteTextFields[moduleFactory];
+
+ if (fteTextFieldDictionary)
+ {
+ for (var iter:Object in fteTextFieldDictionary)
+ {
+ fteTextField = iter;
+ break;
+ }
+ }
+ if (!fteTextField)
+ {
+ if (moduleFactory)
+ {
+ fteTextField = moduleFactory.create(
+ "mx.core.FTETextField");
+ fteTextField.fontContext = moduleFactory;
+ }
+
+ // The dictionary could be empty, but not null because entries in the dictionary
+ // could be garbage collected.
+ if (!fteTextFieldDictionary)
+ fteTextFieldDictionary = new Dictionary(true);
+ fteTextFieldDictionary[fteTextField] = 1;
+ fteTextFields[moduleFactory] = fteTextFieldDictionary;
+ }
+
+ return fteTextField;
+ }
+}
+
+}
diff --git a/src/mx/core/Version.as b/src/mx/core/Version.as
new file mode 100644
index 00000000..3c8ad583
--- /dev/null
+++ b/src/mx/core/Version.as
@@ -0,0 +1,18 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+import mx.core.mx_internal;
+
+/**
+ * @private
+ * Version string for this class.
+ */
+mx_internal static const VERSION:String = "4.6.0.23201";
diff --git a/src/mx/core/mx_internal.as b/src/mx/core/mx_internal.as
new file mode 100644
index 00000000..38d38783
--- /dev/null
+++ b/src/mx/core/mx_internal.as
@@ -0,0 +1,29 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.core
+{
+
+/**
+ * This namespace is used for undocumented APIs -- usually implementation
+ * details -- which can't be private because they need to visible
+ * to other classes.
+ * APIs in this namespace are completely unsupported and are likely to
+ * change in future versions of Flex.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public namespace mx_internal =
+ "http://www.adobe.com/2006/flex/mx/internal";
+}
diff --git a/src/mx/events/CollectionEvent.as b/src/mx/events/CollectionEvent.as
new file mode 100644
index 00000000..02af6ea6
--- /dev/null
+++ b/src/mx/events/CollectionEvent.as
@@ -0,0 +1,275 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.events
+{
+
+import flash.events.Event;
+
+/**
+ * The mx.events.CollectionEvent class represents an event that is
+ * dispatched when the associated collection changes.
+ *
+ * @see FlexEvent#CURSOR_UPDATE
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class CollectionEvent extends Event
+{
+ //include "../core/Version.as";
+
+ import mx.core.mx_internal;
+
+ /**
+ * @private
+ * Version string for this class.
+ */
+ mx_internal static const VERSION:String = "4.1.0.16076";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * The CollectionEvent.COLLECTION_CHANGE constant defines the value of the
+ * type property of the event object for an event that is
+ * dispatched when a collection has changed.
+ *
+ * The properties of the event object have the following values. + * Not all properties are meaningful for all kinds of events. + * See the detailed property descriptions for more information.
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
items | An Array of objects with
+ * information about the items affected by the event.
+ * The contents of this field depend on the event kind;
+ * for details see the items property |
kind | The kind of event. + * The valid values are defined in the CollectionEventKind + * class as constants. |
location | Location within the target collection
+ * of the item(s) specified in the items property. |
oldLocation | the previous location in the collection
+ * of the item specified in the items property. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
type | CollectionEvent.COLLECTION_CHANGE |
null, which indicates that the kind is unknown.
+ *
+ * @param location When the kind is
+ * CollectionEventKind.ADD,
+ * CollectionEventKind.MOVE,
+ * CollectionEventKind.REMOVE, or
+ * CollectionEventKind.REPLACE,
+ * this value indicates at what location the item(s) specified
+ * in the items property can be found
+ * within the target collection.
+ *
+ * @param oldLocation When the kind is
+ * CollectionEventKind.MOVE, this value indicates
+ * the old location within the target collection
+ * of the item(s) specified in the items property.
+ *
+ * @param items Array of objects with information about the items
+ * affected by the event, as described in the items property.
+ * When the kind is CollectionEventKind.REFRESH
+ * or CollectionEventKind.RESET, this Array has zero length.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function CollectionEvent(type:String, bubbles:Boolean = false,
+ cancelable:Boolean = false,
+ kind:String = null, location:int = -1,
+ oldLocation:int = -1, items:Array = null)
+ {
+ super(type, bubbles, cancelable);
+
+ this.kind = kind;
+ this.location = location;
+ this.oldLocation = oldLocation;
+ this.items = items ? items : [];
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // kind
+ //----------------------------------
+
+ /**
+ * Indicates the kind of event that occurred.
+ * The property value can be one of the values in the
+ * CollectionEventKind class,
+ * or null, which indicates that the kind is unknown.
+ *
+ * @default null
+ *
+ * @see CollectionEventKind
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var kind:String;
+
+ //----------------------------------
+ // items
+ //----------------------------------
+
+ /**
+ * When the kind is CollectionEventKind.ADD
+ * or CollectionEventKind.REMOVE the items property
+ * is an Array of added/removed items.
+ * When the kind is CollectionEventKind.REPLACE
+ * or CollectionEventKind.UPDATE the items property
+ * is an Array of PropertyChangeEvent objects with information about the items
+ * affected by the event.
+ * When a value changes, query the newValue and
+ * oldValue fields of the PropertyChangeEvent objects
+ * to find out what the old and new values were.
+ * When the kind is CollectionEventKind.REFRESH
+ * or CollectionEventKind.RESET, this array has zero length.
+ *
+ * @default [ ]
+ *
+ * @see PropertyChangeEvent
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var items:Array;
+
+ //----------------------------------
+ // location
+ //----------------------------------
+
+ /**
+ * When the kind value is CollectionEventKind.ADD,
+ * CollectionEventKind.MOVE,
+ * CollectionEventKind.REMOVE, or
+ * CollectionEventKind.REPLACE, this property is the
+ * zero-base index in the collection of the item(s) specified in the
+ * items property.
+ *
+ * @see CollectionEventKind
+ *
+ * @default -1
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var location:int;
+
+ //----------------------------------
+ // oldLocation
+ //----------------------------------
+
+ /**
+ * When the kind value is CollectionEventKind.MOVE,
+ * this property is the zero-based index in the target collection of the
+ * previous location of the item(s) specified by the items property.
+ *
+ * @default -1
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var oldLocation:int;
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden methods: Object
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override public function toString():String
+ {
+ return formatToString("CollectionEvent", "kind", "location",
+ "oldLocation", "type", "bubbles",
+ "cancelable", "eventPhase");
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden methods: Event
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override public function clone():Event
+ {
+ return new CollectionEvent(type, bubbles, cancelable, kind, location, oldLocation, items);
+ }
+}
+
+}
diff --git a/src/mx/events/CollectionEventKind.as b/src/mx/events/CollectionEventKind.as
new file mode 100644
index 00000000..0950a25b
--- /dev/null
+++ b/src/mx/events/CollectionEventKind.as
@@ -0,0 +1,135 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.events
+{
+
+/**
+ * The CollectionEventKind class contains constants for the valid values
+ * of the mx.events.CollectionEvent class kind property.
+ * These constants indicate the kind of change that was made to the collection.
+ *
+ * @see mx.events.CollectionEvent
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public final class CollectionEventKind
+{
+ //include "../core/Version.as";
+
+ import mx.core.mx_internal;
+
+ /**
+ * @private
+ * Version string for this class.
+ */
+ mx_internal static const VERSION:String = "4.1.0.16076";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Indicates that the collection added an item or items.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const ADD:String = "add";
+
+ /**
+ * Indicates that the item has moved from the position identified
+ * by the CollectionEvent oldLocation property to the
+ * position identified by the location property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const MOVE:String = "move";
+
+ /**
+ * Indicates that the collection applied a sort, a filter, or both.
+ * This change can potentially be easier to handle than a RESET.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const REFRESH:String = "refresh";
+
+ /**
+ * Indicates that the collection removed an item or items.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const REMOVE:String = "remove";
+
+ /**
+ * Indicates that the item at the position identified by the
+ * CollectionEvent location property has been replaced.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const REPLACE:String = "replace";
+
+ /**
+ * Indicates that the collection has internally expanded.
+ * This event kind occurs when a branch opens in a
+ * hierarchical collection, for example when a Tree control branch opens.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ mx_internal static const EXPAND:String = "expand";
+
+ /**
+ * Indicates that the collection has changed so drastically that
+ * a reset is required.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const RESET:String = "reset";
+
+ /**
+ * Indicates that one or more items were updated within the collection.
+ * The affected item(s)
+ * are stored in the items property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const UPDATE:String = "update";
+}
+
+}
diff --git a/src/mx/events/FlexEvent.as b/src/mx/events/FlexEvent.as
new file mode 100644
index 00000000..164d2365
--- /dev/null
+++ b/src/mx/events/FlexEvent.as
@@ -0,0 +1,1467 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.events
+{
+
+import flash.events.Event;
+
+/**
+ * The FlexEvent class represents the event object passed to
+ * the event listener for many Flex events.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class FlexEvent extends Event
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * The FlexEvent.ADD constant defines the value of the
+ * type property of the event object for an add event.
+ *
+ * This event will only be dispatched when there are one or more relevant listeners + * attached to the dispatching object.
+ * + *The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.ADD_FOCUS_MANAGER constant defines the value of the
+ * type property of the event object for an addFocusManager event.
+ * This event is dispatched from an IFocusManagerContainer when its focusManager
+ * is assigned.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.APPLICATION_COMPLETE constant defines the value of the
+ * type property of the event object for a applicationComplete event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.BUTTON_DOWN constant defines the value of the
+ * type property of the event object for a buttonDown event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.BACK_KEY_PRESSED constant defines the value of the
+ * type property of the event object for a backKeyPressed event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | true |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.CHANGE_END constant defines the value of the
+ * type property of the event object for a changeEnd event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.CHANGE_START constant defines the value of the
+ * type property of the event object for a changeStart event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.CHANGING constant defines the value of the
+ * type property of the event object for a changing event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.CREATION_COMPLETE constant defines the value of the
+ * type property of the event object for a creationComplete event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.CONTENT_CREATION_COMPLETE constant defines the value of the
+ * type property of the event object for a contentCreationComplete event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.CURSOR_UPDATE constant defines the value of the
+ * type property of the event object for a cursorUpdate event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.DATA_CHANGE constant defines the value of the
+ * type property of the event object for a dataChange event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.ENTER constant defines the value of the
+ * type property of the event object for a enter event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.ENTER_FRAME constant defines the value of the
+ * type property of the event object for an Event.ENTER_FRAMER event.
+ *
+ * Adding a listener to ENTER_FRAME on the SystemManager will add a listener for
+ * the Event.ENTER_FRAME event on the stage, if access if allowed,
+ * or the SystemManager if access the the stage is not allowed.
+ * The listener should expect to receive Event.ENTER_FRAME events.
+ *
+ * @eventType flexEventEnterFrame
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const ENTER_FRAME:String = "flexEventEnterFrame";
+
+ /**
+ * The FlexEvent.ENTER_STATE constant defines the value of the
+ * type property of the event object for a enterState event.
+ *
+ * This event will only be dispatched when there are one or more relevant listeners + * attached to the dispatching object.
+ * + *The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.EXIT_STATE constant defines the value of the
+ * type property of the event object for a exitState event.
+ *
+ * This event will only be dispatched when there are one or more relevant listeners + * attached to the dispatching object.
+ * + *The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.FLEX_WINDOW_ACTIVATE constant defines the value of the
+ * type property of the event object for a flexWindowActivate
+ * event.
+ *
+ * Similar to the flash.events.AIREvent.WINDOW_ACTIVATE except it is dispatched
+ * in both Flash and AIR when a Flex window or popup is activated. This event is
+ * dispatched from the focusManager managing
+ * focus in that container.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.FLEX_WINDOW_DEACTIVATE constant defines the value of the
+ * type property of the event object for a flexWindowDeactivate
+ * event.
+ *
+ * Similar to the flash.events.AIREvent.FLEX_WINDOW_DEACTIVATE except it is dispatched
+ * in both Flash and AIR when a Flex Window or popup is deactivated. This event is
+ * dispatched from the focusManager managing
+ * focus in that container.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.HIDE constant defines the value of the
+ * type property of the event object for a hide event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.IDLE constant defines the value of the
+ * type property of the event object for a idle event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
This event is always dispatched once by the Preloader class, + * and is the last event that the Preloader dispatches. + * When this event is dispatched, the event listener should + * dispatch an Event.COMPLETE event.
+ * + *A download progress bar must dispatch a complete
+ * event after it has received an init_complete event.
+ * The complete event informs the Preloader that the
+ * download progress bar has completed all operations and can be dismissed.
A download progress bar can perform additional tasks,
+ * such as playing an animation, after receiving
+ * an init_complete event, and before dispatching
+ * the complete event. Dispatching the complete
+ * event should be the last action of the download progress bar.
The FlexEvent.INIT_COMPLETE constant defines the value of the
+ * type property of the event object for a initComplete event.
The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
measure(), commitProperties(),
+ * or updateDisplayList() methods.
+ * This event describes the progress of the application in the initialization phase.
+ * You use this event when creating a custom download progress bar.
+ *
+ * The FlexEvent.INIT_PROGRESS constant defines the value of the
+ * type property of the event object for a initProgress event.
The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.INITIALIZE constant defines the value of the
+ * type property of the event object for a initialize event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.INVALID constant defines the value of the
+ * type property of the event object for a invalid event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.LOADING constant defines the value of the
+ * type property of the event object for a loading event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.MENU_KEY_PRESSED constant defines the value of the
+ * type property of the event object for a menuKeyPressed event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | true |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.MUTED_CHANGE constant defines the value of the
+ * type property of the event object for a mutedChange event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.NAVIGATOR_STATE_LOADING constant defines the value of the
+ * type property of the event object for a navigatorStateLoading event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | true |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.NAVIGATOR_STATE_SAVING constant defines the value of the
+ * type property of the event object for a navigatorStateSaving event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | true |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.PREINITIALIZE constant defines the value of the
+ * type property of the event object for a preinitialize event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.READY constant defines the value of the
+ * type property of the event object for a ready
+ * event. This event is dispatched by the BitmapImage and spark Image
+ * classes to denote that the assigned image source has fully loaded.
+ *
+ * The properties of the event object have the following values:
+ * + *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
returnValue | null |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myImage.addEventListener() to register an event listener,
+ * myImage is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
Type | FlexEvent.READY |
FlexEvent.RENDER constant defines the value of the
+ * type property of the event object for an Event.RENDER event.
+ *
+ * Adding a listener on the SystemManager will add a listener for FlexEvent.RENDER
+ * events on the stage or the SystemManager if the application does not have
+ * access to the stage. The listener will also generate an Event.RENDER event. The
+ * listener function should expect to receive Event.RENDER events.
+ *
+ * @eventType flexEventRender
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const RENDER:String = "flexEventRender";
+
+ /**
+ * The FlexEvent.REMOVE constant defines the value of the
+ * type property of the event object for an remove event.
+ *
+ * This event will only be dispatched when there are one or more relevant listeners + * attached to the dispatching object.
+ * + *The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.REPEAT constant defines the value of the
+ * type property of the event object for a repeat event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.REPEAT_END constant defines the value of the
+ * type property of the event object for a repeatEnd event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.REPEAT_START constant defines the value of the
+ * type property of the event object for a repeatStart event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.SELECTION_CHANGE constant defines the value of the
+ * type property of the event object for a selectionChange event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.SHOW constant defines the value of the
+ * type property of the event object for a show event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.STATE_CHANGE_COMPLETE constant defines the value of the
+ * type property of the event object for a stateChangeComplete event.
+ *
+ * This event will only be dispatched when there are one or more relevant listeners + * attached to the dispatching object.
+ * + *The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.STATE_CHANGE_INTERRUPTED constant defines the value of the
+ * type property of the event object for a stateChangeInterrupted event.
+ *
+ * This event will only be dispatched when there are one or more relevant listeners + * attached to the dispatching object.
+ * + *The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.TRANSFORM_CHANGE constant defines the value of the
+ * type property of the event object for a transformChange event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.TRANSITION_START constant defines the value of the
+ * type property of the event object for a transitionStart event.
+ *
+ * This event will only be dispatched when there are one or more relevant listeners + * attached to the dispatching object.
+ * + *The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.TRANSITION_END constant defines the value of the
+ * type property of the event object for a transitionEnd event.
+ *
+ * This event will only be dispatched when there are one or more relevant listeners + * attached to the dispatching object.
+ * + *The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.UPDATE_COMPLETE constant defines the value of the
+ * type property of the event object for a updateComplete event.
+ *
+ * This event will only be dispatched when there are one or more relevant listeners + * attached to the dispatching object.
+ * + *The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.URL_CHANGED constant defines the value of the
+ * type property of the event object for a urlChanged event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.VALID constant defines the value of the
+ * type property of the event object for a valid event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
FlexEvent.VALUE_COMMIT constant defines the value of the
+ * type property of the event object for a valueCommit
+ * event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
ModuleEvent.ERROR constant defines the value of the
+ * type property of the event object for an error event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
bytesLoaded | Empty |
bytesTotal | Empty |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
errorText | The error message. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
ModuleEvent.PROGRESS constant defines the value of the
+ * type property of the event object for a progress event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
bytesLoaded | The number of bytes loaded. |
bytesTotal | The total number of bytes to load. |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
errorText | Empty |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
ModuleEvent.READY constant defines the value of the
+ * type property of the event object for a complete event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
bytesLoaded | The number of bytes loaded. |
bytesTotal | The total number of bytes to load. |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
errorText | Empty |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
IFlexModuleFactory.info()
+ * method on the module.
+ * The ModuleEvent.SETUP constant defines the value of the
+ * type property of the event object for a setup event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
bytesLoaded | Empty |
bytesTotal | Empty |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
errorText | An error message. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
ModuleEvent.UNLOAD constant defines the value of the
+ * type property of the event object for an unload event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
bytesLoaded | Empty |
bytesTotal | Empty |
cancelable | false |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
errorText | An error message. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
ModuleEvent.PROGRESS);ModuleEvent.READY);ModuleEvent.SETUP);ModuleEvent.ERROR);ModuleEvent.UNLOAD);ModuleEvent.ERROR.
+ *
+ * @param module An instance of an interface for a particular module. .
+ *
+ * @tiptext Constructor for ModuleEvent objects.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function ModuleEvent(type:String, bubbles:Boolean = false,
+ cancelable:Boolean = false,
+ bytesLoaded:uint = 0, bytesTotal:uint = 0,
+ errorText:String = null, module:IModuleInfo = null)
+ {
+ super(type, bubbles, cancelable, bytesLoaded, bytesTotal);
+
+ this.errorText = errorText;
+ this._module = module;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // errorText
+ //----------------------------------
+
+ /**
+ * The error message if the type is ModuleEvent.ERROR;
+ * otherwise, it is null.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var errorText:String;
+
+ //----------------------------------
+ // module
+ //----------------------------------
+
+ private var _module:IModuleInfo;
+
+ /**
+ * The target, which is an instance of an
+ * interface for a particular module.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get module():IModuleInfo
+ {
+ if (_module) return _module;
+ return target as IModuleInfo;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden properties: Event
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override public function clone():Event
+ {
+ return new ModuleEvent(type, bubbles, cancelable,
+ bytesLoaded, bytesTotal, errorText, module);
+ }
+}
+
+}
diff --git a/src/mx/events/PropertyChangeEvent.as b/src/mx/events/PropertyChangeEvent.as
new file mode 100644
index 00000000..4e69c341
--- /dev/null
+++ b/src/mx/events/PropertyChangeEvent.as
@@ -0,0 +1,282 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.events
+{
+
+import flash.events.Event;
+import mx.events.PropertyChangeEventKind;
+
+/**
+ * The PropertyChangeEvent class represents the event object
+ * passed to the event listener when one of the properties of
+ * an object has changed, and provides information about the change.
+ * This event is used by collection classes, and is the only way for
+ * collections to know that the data they represent has changed.
+ * This event is also used by the Flex data binding mechanism.
+ *
+ * @see PropertyChangeEventKind
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class PropertyChangeEvent extends Event
+{
+ //include "../core/Version.as";
+
+ import mx.core.mx_internal;
+
+ /**
+ * @private
+ * Version string for this class.
+ */
+ mx_internal static const VERSION:String = "4.1.0.16076";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ // Note: If the value for CHANGE changes,
+ // update mx.utils.ObjectProxy's Bindable metadata.
+
+ /**
+ * The PropertyChangeEvent.PROPERTY_CHANGE constant defines the value of the
+ * type property of the event object for a PropertyChange event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | Determined by the constructor; defaults to false. |
cancelable | Determined by the constructor; defaults to false. |
kind | The kind of change; PropertyChangeEventKind.UPDATE + * or PropertyChangeEventKind.DELETE. |
oldValue | The original property value. |
newValue | The new property value, if any. |
property | The property that changed. |
source | The object that contains the property that changed. |
currentTarget | The Object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of the currentTarget. |
target | The Object that dispatched the event;
+ * it is not always the Object listening for the event.
+ * Use the currentTarget property to always access the
+ * Object listening for the event. |
PropertyChangeEventKind.UPDATE
+ * with the specified properties.
+ * This is a convenience method.
+ *
+ * @param source The object where the change occured.
+ *
+ * @param property A String, QName, or int
+ * specifying the property that changed,
+ *
+ * @param oldValue The value of the property before the change.
+ *
+ * @param newValue The value of the property after the change.
+ *
+ * @return A newly constructed PropertyChangeEvent
+ * with the specified properties.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function createUpdateEvent(
+ source:Object,
+ property:Object,
+ oldValue:Object,
+ newValue:Object):PropertyChangeEvent
+ {
+ var event:PropertyChangeEvent =
+ new PropertyChangeEvent(PROPERTY_CHANGE);
+
+ event.kind = PropertyChangeEventKind.UPDATE;
+ event.oldValue = oldValue;
+ event.newValue = newValue;
+ event.source = source;
+ event.property = property;
+
+ return event;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param type The event type; indicates the action that triggered the event.
+ *
+ * @param bubbles Specifies whether the event can bubble
+ * up the display list hierarchy.
+ *
+ * @param cancelable Specifies whether the behavior
+ * associated with the event can be prevented.
+ *
+ * @param kind Specifies the kind of change.
+ * The possible values are PropertyChangeEventKind.UPDATE,
+ * PropertyChangeEventKind.DELETE, and null.
+ *
+ * @param property A String, QName, or int
+ * specifying the property that changed.
+ *
+ * @param oldValue The value of the property before the change.
+ *
+ * @param newValue The value of the property after the change.
+ *
+ * @param source The object that the change occured on.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function PropertyChangeEvent(type:String, bubbles:Boolean = false,
+ cancelable:Boolean = false,
+ kind:String = null,
+ property:Object = null,
+ oldValue:Object = null,
+ newValue:Object = null,
+ source:Object = null)
+ {
+ super(type, bubbles, cancelable);
+
+ this.kind = kind;
+ this.property = property;
+ this.oldValue = oldValue;
+ this.newValue = newValue;
+ this.source = source;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // kind
+ //----------------------------------
+
+ /**
+ * Specifies the kind of change.
+ * The possible values are PropertyChangeEventKind.UPDATE,
+ * PropertyChangeEventKind.DELETE, and null.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var kind:String;
+
+ //----------------------------------
+ // newValue
+ //----------------------------------
+
+ /**
+ * The value of the property after the change.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var newValue:Object;
+
+ //----------------------------------
+ // oldValue
+ //----------------------------------
+
+ /**
+ * The value of the property before the change.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var oldValue:Object;
+
+ //----------------------------------
+ // property
+ //----------------------------------
+
+ /**
+ * A String, QName, or int specifying the property that changed.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var property:Object;
+
+ //----------------------------------
+ // source
+ //----------------------------------
+
+ /**
+ * The object that the change occured on.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var source:Object;
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods: Event
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override public function clone():Event
+ {
+ return new PropertyChangeEvent(type, bubbles, cancelable, kind,
+ property, oldValue, newValue, source);
+ }
+}
+
+}
diff --git a/src/mx/events/PropertyChangeEventKind.as b/src/mx/events/PropertyChangeEventKind.as
new file mode 100644
index 00000000..9f584e6b
--- /dev/null
+++ b/src/mx/events/PropertyChangeEventKind.as
@@ -0,0 +1,65 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.events
+{
+
+/**
+ * The PropertyChangeEventKind class defines the constant values
+ * for the kind property of the PropertyChangeEvent class.
+ *
+ * @see mx.events.PropertyChangeEvent
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public final class PropertyChangeEventKind
+{
+ //include "../core/Version.as";
+
+ import mx.core.mx_internal;
+
+ /**
+ * @private
+ * Version string for this class.
+ */
+ mx_internal static const VERSION:String = "4.1.0.16076";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Indicates that the value of the property changed.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const UPDATE:String = "update";
+
+ /**
+ * Indicates that the property was deleted from the object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const DELETE:String = "delete";
+}
+
+}
diff --git a/src/mx/events/ResourceEvent.as b/src/mx/events/ResourceEvent.as
new file mode 100644
index 00000000..993fc730
--- /dev/null
+++ b/src/mx/events/ResourceEvent.as
@@ -0,0 +1,216 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.events
+{
+
+import flash.events.Event;
+import flash.events.ProgressEvent;
+
+/**
+ * The ResourceEvent class represents an Event object that is dispatched
+ * when the ResourceManager loads the resource bundles in a resource module
+ * by calling the loadResourceModule() method.
+ *
+ * @see mx.resources.ResourceManager
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class ResourceEvent extends ProgressEvent
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Dispatched when the resource module SWF file has finished loading.
+ * The ResourceEvent.COMPLETE constant defines the value of the
+ * type property of the event object for a complete event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
cancelable | false |
currentTarget | The object that defines the
+ * event listener that handles the event. For example, if you use
+ * myButton.addEventListener() to register an event listener,
+ * myButton is the value of currentTarget. |
errorText | Empty |
target | The object that dispatched the event;
+ * it is not always the object listening for the event.
+ * Use the currentTarget property to always access the
+ * object that listens for the event. |
type property of the event object for a error event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
bytesLoaded | Empty |
bytesTotal | Empty |
cancelable | false |
currentTarget | The object that defines the
+ * event listener that handles the event. For example, if you use the
+ * myButton.addEventListener() method to register an event listener,
+ * myButton is the value of currentTarget. |
errorText | An error message.|
target | The object that dispatched the event;
+ * it is not always the object that is listening for the event.
+ * Use the currentTarget property to always access the
+ * object that listens for the event. |
type property of the event object for a progress event.
+ *
+ * The properties of the event object have the following values:
+ *| Property | Value |
|---|---|
bubbles | false |
bytesLoaded | The number of bytes loaded. |
bytesTotal | The total number of bytes to load. |
cancelable | false |
currentTarget | The object that defines the
+ * event listener that handles the event. For example, if you use the
+ * myButton.addEventListener() method to register an event listener,
+ * myButton is the value of currentTarget. |
errorText | Empty|
target | The object that dispatched the event;
+ * it is not always the object that listens for the event.
+ * Use the currentTarget property to always access the
+ * object that is listening for the event. |
type property of the event object. Possible values are:
+ * "progress" (ResourceEvent.PROGRESS)"complete" (ResourceEvent.COMPLETE)"error" (ResourceEvent.ERROR)type is ResourceEvent.ERROR.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function ResourceEvent(type:String, bubbles:Boolean = false,
+ cancelable:Boolean = false,
+ bytesLoaded:uint = 0, bytesTotal:uint = 0,
+ errorText:String = null)
+ {
+ super(type, bubbles, cancelable, bytesLoaded, bytesTotal);
+
+ this.errorText = errorText;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // errorText
+ //----------------------------------
+
+ /**
+ * The error message if the type is ERROR;
+ * otherwise, it is null.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var errorText:String;
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden properties: Event
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override public function clone():Event
+ {
+ return new ResourceEvent(type, bubbles, cancelable,
+ bytesLoaded, bytesTotal, errorText);
+ }
+}
+
+}
diff --git a/src/mx/geom/CompoundTransform.as b/src/mx/geom/CompoundTransform.as
new file mode 100644
index 00000000..ea436cb7
--- /dev/null
+++ b/src/mx/geom/CompoundTransform.as
@@ -0,0 +1,759 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2003-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+package mx.geom
+{
+ //import __AS3__.vec.Vector;
+
+ import flash.events.Event;
+ import flash.geom.Matrix;
+ import flash.geom.Matrix3D;
+ import flash.geom.Point;
+ import flash.geom.Vector3D;
+
+ import mx.core.AdvancedLayoutFeatures;
+ import mx.utils.MatrixUtil;
+
+ /**
+ * A CompoundTransform represents a 2D or 3D matrix transform. A compound transform represents a matrix that can be queried or set either as a 2D matrix,
+ * a 3D matrix, or as individual convenience transform properties such as x, y, scaleX, rotationZ, etc.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public class CompoundTransform
+ {
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function CompoundTransform()
+ {
+ }
+
+
+
+ /**
+ * @private
+ * storage for transform properties. These values are concatenated together with the layout properties to
+ * form the actual computed matrix used to render the object.
+ */
+ private var _rotationX:Number = 0;
+ private var _rotationY:Number = 0;
+ private var _rotationZ:Number = 0;
+ private var _scaleX:Number = 1;
+ private var _scaleY:Number = 1;
+ private var _scaleZ:Number = 1;
+ private var _x:Number = 0;
+ private var _y:Number = 0;
+ private var _z:Number = 0;
+
+ private var _transformX:Number = 0;
+ private var _transformY:Number = 0;
+ private var _transformZ:Number = 0;
+
+
+ /**
+ * @private
+ * slots for the 2D and 3D matrix transforms. Note that
+ * these are only allocated and computed on demand -- many component instances will never use a 3D
+ * matrix, for example.
+ */
+ private var _matrix:Matrix;
+ private var _matrix3D:Matrix3D;
+
+
+ /**
+ * @private
+ * bit field flags for indicating which transforms are valid -- the layout properties, the matrices,
+ * and the 3D matrices. Since developers can set any of the three programmatically, the last one set
+ * will always be valid, and the others will be invalid until validated on demand.
+ */
+ private static const MATRIX_VALID:uint = 0x20;
+ private static const MATRIX3D_VALID:uint = 0x40;
+ private static const PROPERTIES_VALID:uint = 0x80;
+
+
+ /**
+ * @private
+ * flags for tracking whether the transform is 3D. A transform is 3D if any of the 3D properties -- rotationX/Y, scaleZ, or z -- are set.
+ */
+ private static const IS_3D:uint = 0x200;
+ private static const M3D_FLAGS_VALID:uint = 0x400;
+
+ /**
+ * @private
+ * constants to indicate which form of a transform -- the properties, matrix, or matrix3D -- is
+ * 'the source of truth.'
+ */
+ public static const SOURCE_PROPERTIES:uint = 1;
+ public static const SOURCE_MATRIX:uint = 2;
+ public static const SOURCE_MATRIX3D:uint = 3;
+
+ /**
+ * @private
+ * indicates the 'source of truth' for the transform.
+ */
+ public var sourceOfTruth:uint = SOURCE_PROPERTIES;
+
+ /**
+ * @private
+ * general storage for all of ur flags.
+ */
+ private var _flags:uint = PROPERTIES_VALID;
+
+ /**
+ * @private
+ * flags that get passed to the invalidate method indicating why the invalidation is happening.
+ */
+ private static const INVALIDATE_FROM_NONE:uint = 0;
+ private static const INVALIDATE_FROM_PROPERTY:uint = 4;
+ private static const INVALIDATE_FROM_MATRIX:uint = 5;
+ private static const INVALIDATE_FROM_MATRIX3D:uint = 6;
+
+ /**
+ * @private
+ * static data used by utility methods below
+ */
+ private static var decomposition:Vector.true to cause the fill to tile outward
+ * to the edges of the filled region.
+ * Set to false to end the fill at the edge of the region.
+ *
+ * @default true
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get repeat():Boolean
+ {
+ return _fillMode == BitmapFillMode.REPEAT;
+ }
+
+ public function set repeat(value:Boolean):void
+ {
+ var oldValue:Boolean = (_fillMode == BitmapFillMode.REPEAT);
+ if (value != oldValue)
+ {
+ //Setting repeat just sets fillMode to repeat
+ fillMode = value ? BitmapFillMode.REPEAT : BitmapFillMode.SCALE;
+ dispatchFillChangedEvent("repeat", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // fillMode
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ protected var _fillMode:String = BitmapFillMode.SCALE;
+
+ [Inspectable(category="General", enumeration="clip,repeat,scale", defaultValue="scale")]
+
+ /**
+ * Determines how the bitmap fills in the dimensions. If you set the value
+ * of this property in a tag, use the string (such as "repeat"). If you set the value of
+ * this property in ActionScript, use the constant (such as BitmapFillMode.CLIP).
+ *
+ * When set to BitmapFillMode.CLIP ("clip"), the bitmap
+ * ends at the edge of the region.
+ *
+ * When set to BitmapFillMode.REPEAT ("repeat"), the bitmap
+ * repeats to fill the region.
+ *
+ * When set to BitmapFillMode.SCALE ("scale"), the bitmap
+ * stretches to fill the region.
+ *
+ * @default BitmapFillMode.SCALE
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get fillMode():String
+ {
+ return _fillMode;
+ }
+
+ /**
+ * @private
+ */
+ public function set fillMode(value:String):void
+ {
+ var oldValue:String = _fillMode;
+ if (value != _fillMode)
+ {
+ _fillMode = value;
+ dispatchFillChangedEvent("fillMode", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // rotation
+ //----------------------------------
+
+ private var _rotation:Number = 0;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * The number of degrees to rotate the bitmap.
+ * Valid values range from 0.0 to 360.0.
+ *
+ * @default 0
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get rotation():Number
+ {
+ return compoundTransform ? compoundTransform.rotationZ : _rotation;
+ }
+
+ public function set rotation(value:Number):void
+ {
+ if (value != rotation)
+ {
+ var oldValue:Number = rotation;
+
+ if (compoundTransform)
+ compoundTransform.rotationZ = value;
+ else
+ _rotation = value;
+ dispatchFillChangedEvent("rotation", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // scaleX
+ //----------------------------------
+
+ private var _scaleX:Number;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * The percent to horizontally scale the bitmap when filling,
+ * from 0.0 to 1.0.
+ * If 1.0, the bitmap is filled at its natural size.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get scaleX():Number
+ {
+ return compoundTransform ? compoundTransform.scaleX : _scaleX;
+ }
+
+ /**
+ * @private
+ */
+ public function set scaleX(value:Number):void
+ {
+ if (value != scaleX)
+ {
+ var oldValue:Number = scaleX;
+
+ if (compoundTransform)
+ {
+ // If we have a compoundTransform, only non-NaN values are allowed
+ if (!isNaN(value))
+ compoundTransform.scaleX = value;
+ }
+ else
+ {
+ _scaleX = value;
+ }
+ dispatchFillChangedEvent("scaleX", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // scaleY
+ //----------------------------------
+
+ private var _scaleY:Number;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * The percent to vertically scale the bitmap when filling,
+ * from 0.0 to 1.0.
+ * If 1.0, the bitmap is filled at its natural size.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get scaleY():Number
+ {
+ return compoundTransform ? compoundTransform.scaleY : _scaleY;
+ }
+
+ /**
+ * @private
+ */
+ public function set scaleY(value:Number):void
+ {
+ if (value != scaleY)
+ {
+ var oldValue:Number = scaleY;
+
+ if (compoundTransform)
+ {
+ // If we have a compoundTransform, only non-NaN values are allowed
+ if (!isNaN(value))
+ compoundTransform.scaleY = value;
+ }
+ else
+ {
+ _scaleY = value;
+ }
+ dispatchFillChangedEvent("scaleY", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // source
+ //----------------------------------
+
+ private var _source:Object;
+
+ [Inspectable(category="General")]
+
+ /**
+ * The source used for the bitmap fill.
+ * The fill can render from various graphical sources,
+ * including the following:
+ * angle property to control the transition direction.
+ * For example, a value of 180.0 causes the transition
+ * to occur from right to left, rather than from left to right.
+ *
+ * @default 0.0
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get angle():Number
+ {
+ return _angle / Math.PI * 180;
+ }
+
+ /**
+ * @private
+ */
+ public function set angle(value:Number):void
+ {
+ var oldValue:Number = _angle;
+ _angle = value / 180 * Math.PI;
+
+ dispatchGradientChangedEvent("angle", oldValue, _angle);
+ }
+
+ //----------------------------------
+ // compoundTransform
+ //----------------------------------
+
+ /**
+ * Holds the matrix and the convenience transform properties (x, y, and rotation).
+ * The compoundTransform is only created when the matrix property is set.
+ */
+ protected var compoundTransform:CompoundTransform;
+
+ //----------------------------------
+ // entries
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the entries property.
+ */
+ private var _entries:Array = [];
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General", arrayType="mx.graphics.GradientEntry")]
+
+ /**
+ * An Array of GradientEntry objects
+ * defining the fill patterns for the gradient fill.
+ *
+ * @default []
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get entries():Array
+ {
+ return _entries;
+ }
+
+ /**
+ * @private
+ */
+ public function set entries(value:Array):void
+ {
+ var oldValue:Array = _entries;
+ _entries = value;
+
+ processEntries();
+
+ dispatchGradientChangedEvent("entries", oldValue, value);
+ }
+
+ //----------------------------------
+ // interpolationMethod
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the interpolationMethod property.
+ */
+ private var _interpolationMethod:String = "rgb";
+
+ [Inspectable(category="General", enumeration="rgb,linearRGB", defaultValue="rgb")]
+
+ /**
+ * A value from the InterpolationMethod class
+ * that specifies which interpolation method to use.
+ *
+ * Valid values are InterpolationMethod.LINEAR_RGB
+ * and InterpolationMethod.RGB.
The gradient scaleX and scaleY properties represent pixels while the Matrix scale properties represent multipliers.
+ * Thus they are not compatible.
+ * Another difference is the most of the transform properties (x, y, scaleX, and scaleY)
+ * support NaN values while the matrix does not. A NaN value means that the gradient will choose an appropriate value.
The scaleX and scaleY properties can not be represented by the matrix.
+ * Once the matrix is set, scaleX and scaleY can no longer be set.
+ * Also, x and y can not be set to NaN.
+ * The matrix can be set back to null which also resets all of the convenience transform properties back to their default values.
If the matrix is set, then the gradient draw logic will scale the gradient to fit the bounds of the graphic element. + * It will then position the gradient in the upper left corner of the graphic element. + * Finally, it will apply the matrix transformations.
+ + *By default, the LinearGradientStroke defines a transition
+ * from left to right across the control.
+ * Use the rotation property to control the transition direction.
+ * For example, a value of 180.0 causes the transition
+ * to occur from right to left, rather than from left to right.
rotation property to control the transition direction.
+ * For example, a value of 180.0 causes the transition
+ * to occur from right to left, rather than from left to right.
+ *
+ * @default 0.0
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get rotation():Number
+ {
+ return compoundTransform ? compoundTransform.rotationZ : _rotation;
+ }
+
+ /**
+ * @private
+ */
+ public function set rotation(value:Number):void
+ {
+ if (value != rotation)
+ {
+ var oldValue:Number = rotation;
+
+ if (compoundTransform)
+ compoundTransform.rotationZ = value;
+ else
+ _rotation = value;
+ dispatchGradientChangedEvent("rotation", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // spreadMethod
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the spreadMethod property.
+ */
+ private var _spreadMethod:String = "pad";
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General", enumeration="pad,reflect,repeat", defaultValue="pad")]
+
+ /**
+ * A value from the SpreadMethod class
+ * that specifies which spread method to use.
+ *
+ * Valid values are SpreadMethod.PAD,
+ * SpreadMethod.REFLECT,
+ * and SpreadMethod.REPEAT.
entries
+ * Array into the internal colors, ratios,
+ * and alphas arrays.
+ */
+ private function processEntries():void
+ {
+ colors = [];
+ ratios = [];
+ alphas = [];
+
+ if (!_entries || _entries.length == 0)
+ return;
+
+ var ratioConvert:Number = 255;
+
+ var i:int;
+
+ var n:int = _entries.length;
+ for (i = 0; i < n; i++)
+ {
+ var e:GradientEntry = _entries[i];
+ e.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE,
+ entry_propertyChangeHandler, false, 0, true);
+ colors.push(e.color);
+ alphas.push(e.alpha);
+ ratios.push(e.ratio * ratioConvert);
+ }
+
+ if (isNaN(ratios[0]))
+ ratios[0] = 0;
+
+ if (isNaN(ratios[n - 1]))
+ ratios[n - 1] = 255;
+
+ i = 1;
+
+ while (true)
+ {
+ while (i < n && !isNaN(ratios[i]))
+ {
+ i++;
+ }
+
+ if (i == n)
+ break;
+
+ var start:int = i - 1;
+
+ while (i < n && isNaN(ratios[i]))
+ {
+ i++;
+ }
+
+ var br:Number = ratios[start];
+ var tr:Number = ratios[i];
+
+ for (var j:int = 1; j < i - start; j++)
+ {
+ ratios[j] = br + j * (tr - br) / (i - start);
+ }
+ }
+ }
+
+ /**
+ * Dispatch a gradientChanged event.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ mx_internal function dispatchGradientChangedEvent(prop:String,
+ oldValue:*, value:*):void
+ {
+ dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, prop,
+ oldValue, value));
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Event handlers
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private function entry_propertyChangeHandler(event:Event):void
+ {
+ processEntries();
+
+ dispatchGradientChangedEvent("entries", entries, entries);
+ }
+}
+
+}
diff --git a/src/mx/graphics/GradientEntry.as b/src/mx/graphics/GradientEntry.as
new file mode 100644
index 00000000..7a442f4f
--- /dev/null
+++ b/src/mx/graphics/GradientEntry.as
@@ -0,0 +1,222 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2004-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.graphics
+{
+
+import flash.events.Event;
+import flash.events.EventDispatcher;
+import mx.events.PropertyChangeEvent;
+
+/**
+ * The GradientEntry class defines the objects
+ * that control a transition as part of a gradient fill.
+ * You use this class with the LinearGradient and RadialGradient classes
+ * to define a gradient fill.
+ *
+ * @mxml
+ *
+ * The <mx:GradientEntry> tag inherits all the tag attributes
+ * of its superclass, and adds the following tag attributes:
+ * <mx:GradientEntry + * Properties + * alpha="1.0" + * color="0x000000" + * ratio="-1" + * /> + *+ * + * @see mx.graphics.LinearGradient + * @see mx.graphics.RadialGradient + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class GradientEntry extends EventDispatcher +{ + //include "../core/Version.as"; + + import mx.core.mx_internal; + + /** + * @private + * Version string for this class. + */ + mx_internal static const VERSION:String = "4.1.0.16076"; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @param color The color for this gradient entry. + * The default value is 0x000000 (black). + * + * @param ratio Where in the graphical element the associated color is + * sampled at 100%. + * Flex uniformly spaces any GradientEntries + * with missing ratio values. + * The default value is NaN. + * + * @param alpha The alpha value for this entry in the gradient. + * This parameter is optional. The default value is 1.0. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function GradientEntry(color:uint = 0x000000, + ratio:Number = NaN, + alpha:Number = 1.0) + { + super(); + + this.color = color; + this.ratio = ratio; + this.alpha = alpha; + } + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // alpha + //---------------------------------- + + private var _alpha:Number = 1.0; + + [Bindable("propertyChange")] + [Inspectable(category="General", defaultValue="1", minValue="0.0", maxValue="1.0")] + + /** + * The transparency of a gradient fill. + * Possible values are 0.0 (invisible) through 1.0 (opaque). + * + * @default 1.0 + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get alpha():Number + { + return _alpha; + } + + public function set alpha(value:Number):void + { + var oldValue:Number = _alpha; + if (value != oldValue) + { + _alpha = value; + dispatchEntryChangedEvent("alpha", oldValue, value); + } + } + + //---------------------------------- + // color + //---------------------------------- + + private var _color:uint; + + [Bindable("propertyChange")] + [Inspectable(category="General", format="Color")] + + /** + * The color value for a gradient fill. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get color():uint + { + return _color; + } + + public function set color(value:uint):void + { + var oldValue:uint = _color; + if (value != oldValue) + { + _color = value; + dispatchEntryChangedEvent("color", oldValue, value); + } + } + + //---------------------------------- + // ratio + //---------------------------------- + + private var _ratio:Number; + + [Bindable("propertyChange")] + [Inspectable(category="General", minValue="0.0", maxValue="1.0")] + + /** + * Where in the graphical element, as a percentage from 0.0 to 1.0, + * Flex samples the associated color at 100%. + * For example, a ratio of 0.33 means Flex begins the transition + * to that color 33% of the way through the graphical element. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get ratio():Number + { + return _ratio; + } + + public function set ratio(value:Number):void + { + var oldValue:Number = _ratio; + if (value != oldValue) + { + _ratio = value; + dispatchEntryChangedEvent("ratio", oldValue, value); + } + } + + //-------------------------------------------------------------------------- + // + // Methods + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + private function dispatchEntryChangedEvent(prop:String, + oldValue:*, value:*):void + { + if (hasEventListener("propertyChange")) + dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, prop, + oldValue, value)); + } +} + +} diff --git a/src/mx/graphics/GradientStroke.as b/src/mx/graphics/GradientStroke.as new file mode 100644 index 00000000..2212eab0 --- /dev/null +++ b/src/mx/graphics/GradientStroke.as @@ -0,0 +1,488 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2008 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.graphics +{ +import flash.display.CapsStyle; +import flash.display.Graphics; +import flash.display.GraphicsGradientFill; +import flash.display.GraphicsStroke; +import flash.display.JointStyle; +import flash.geom.Point; +import flash.geom.Rectangle; + +import mx.core.mx_internal; + +use namespace mx_internal; + +/** + * The GradientStroke class lets you specify a gradient filled stroke. + * You use the GradientStroke class, along with the GradientEntry class, + * to define a gradient stroke. + * + * @see mx.graphics.Stroke + * @see mx.graphics.GradientEntry + * @see flash.display.Graphics + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class GradientStroke extends GradientBase implements IStroke +{ + /** + * Constructor. + * + * @param weight Specifies the line weight, in pixels. + * This parameter is optional, + * with a default value of
1.
+ *
+ * @param pixelHinting A Boolean value that specifies
+ * whether to hint strokes to full pixels.
+ * This affects both the position of anchors of a curve
+ * and the line stroke size itself.
+ * With pixelHinting set to true,
+ * Flash Player and AIR hint line widths to full pixel widths.
+ * With pixelHinting set to false,
+ * disjoints can appear for curves and straight lines.
+ * This parameter is optional,
+ * with a default value of false.
+ *
+ * @param scaleMode A value from the LineScaleMode class
+ * that specifies which scale mode to use.
+ * Valid values are LineScaleMode.HORIZONTAL,
+ * LineScaleMode.NONE, LineScaleMode.NORMAL,
+ * and LineScaleMode.VERTICAL.
+ * This parameter is optional,
+ * with a default value of LineScaleMode.NORMAL.
+ *
+ * @param caps A value from the CapsStyle class
+ * that specifies the type of caps at the end of lines.
+ * Valid values are CapsStyle.NONE,
+ * CapsStyle.ROUND, and CapsStyle.SQUARE.
+ * A null value is equivalent to
+ * CapsStyle.ROUND.
+ * This parameter is optional,
+ * with a default value of CapsStyle.ROUND.
+ *
+ * @param joints A value from the JointStyle class
+ * that specifies the type of joint appearance used at angles.
+ * Valid values are JointStyle.BEVEL,
+ * JointStyle.MITER, and JointStyle.ROUND.
+ * A null value is equivalent to
+ * JointStyle.ROUND.
+ * This parameter is optional,
+ * with a default value of JointStyle.ROUND.
+ *
+ * @param miterLimit A number that indicates the limit
+ * at which a miter is cut off.
+ * Valid values range from 1 to 255
+ * (and values outside of that range are rounded to 1 or 255).
+ * This value is only used if the jointStyle property
+ * is set to miter.
+ * The miterLimit value represents the length that a miter
+ * can extend beyond the point at which the lines meet to form a joint.
+ * The value expresses a factor of the line thickness.
+ * For example, with a miterLimit factor of 2.5 and a
+ * thickness of 10 pixels, the miter is cut off at 25 pixels.
+ * This parameter is optional,
+ * with a default value of 3.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function GradientStroke(weight:Number = 1,
+ pixelHinting:Boolean = false,
+ scaleMode:String = "normal",
+ caps:String = "round",
+ joints:String = "round",
+ miterLimit:Number = 3)
+ {
+ super();
+
+ this.weight = weight;
+ this.pixelHinting = pixelHinting;
+ this.scaleMode = scaleMode;
+ this.caps = caps;
+ this.joints = joints;
+ this.miterLimit = miterLimit;
+ }
+
+ //----------------------------------
+ // caps
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the caps property.
+ */
+ private var _caps:String = CapsStyle.ROUND;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General", enumeration="round,square,none", defaultValue="round")]
+
+ /**
+ * Specifies the appearance of the ends of lines.
+ *
+ * Valid values are CapsStyle.NONE,
+ * CapsStyle.ROUND, and CapsStyle.SQUARE.
+ * A null value is equivalent to
+ * CapsStyle.ROUND.
Valid values are JointStyle.BEVEL,
+ * JointStyle.MITER, and JointStyle.ROUND.
+ * A null value is equivalent to
+ * JointStyle.ROUND.
Valid values range from 0 to 255 + * (and values outside of that range are rounded to 0 or 255).
+ * + *This value is only used if the jointStyle property
+ * is set to JointStyle.MITER.
The value of the miterLimit property represents the length that a miter
+ * can extend beyond the point at which the lines meet to form a joint.
+ * The value expresses a factor of the line thickness.
+ * For example, with a miterLimit factor of 2.5
+ * and a thickness of 10 pixels,
+ * the miter is cut off at 25 pixels.
This affects both the position of anchors of a curve + * and the line stroke size itself.
+ * + *With pixelHinting set to true,
+ * Flash Player and AIR hint line widths to full pixel widths.
+ * With pixelHinting set to false,
+ * disjoints can appear for curves and straight lines.
LineScaleMode.NORMAL
+ * Always scale the line thickness when the object is scaled (the default).
+ * LineScaleMode.NONE
+ * Never scale the line thickness.
+ * LineScaleMode.VERTICAL
+ * Do not scale the line thickness if the object is scaled vertically
+ * only.
+ * LineScaleMode.HORIZONTAL
+ * Do not scale the line thickness if the object is scaled horizontally
+ * only.
+ * target.
+ * If the dimensions of the Rectangle are larger than the dimensions
+ * of the target, the fill is clipped.
+ * If the dimensions of the Rectangle are smaller than the dimensions
+ * of the target, the fill expands to fill the entire
+ * target.
+ *
+ * @param targetOrigin The Point that defines the origin (0,0) of the shape in the
+ * coordinate system of target.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function begin(target:Graphics, targetBounds:Rectangle, targetOrigin:Point):void;
+
+ /**
+ * Ends the fill.
+ *
+ * @param target The Graphics object that is being filled.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function end(target:Graphics):void;
+}
+
+}
diff --git a/src/mx/graphics/IStroke.as b/src/mx/graphics/IStroke.as
new file mode 100644
index 00000000..582a326b
--- /dev/null
+++ b/src/mx/graphics/IStroke.as
@@ -0,0 +1,175 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.graphics
+{
+
+import flash.display.Graphics;
+import flash.display.GraphicsStroke;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+
+/**
+ * Defines the interface that classes that define a line must implement.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public interface IStroke
+{
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // weight
+ //----------------------------------
+
+ /**
+ * The line weight, in pixels.
+ * For many chart lines, the default value is 1 pixel.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get weight():Number;
+
+ /**
+ * @private
+ */
+ function set weight(value:Number):void;
+
+ //----------------------------------
+ // scaleMode
+ //----------------------------------
+
+ /**
+ * A value from the LineScaleMode class
+ * that specifies which scale mode to use.
+ * Value valids are:
+ *
+ * LineScaleMode.NORMAL
+ * Always scale the line thickness when the object is scaled (the default).
+ * LineScaleMode.NONE
+ * Never scale the line thickness.
+ * LineScaleMode.VERTICAL
+ * Do not scale the line thickness if the object is scaled vertically
+ * only.
+ * LineScaleMode.HORIZONTAL
+ * Do not scale the line thickness if the object is scaled horizontally
+ * only.
+ * JointStyle.ROUND, JointStyle.MITER,
+ * and JointStyle.BEVEL.
+ *
+ * @see flash.display.JoingStyle
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get joints():String;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Applies the properties to the specified Graphics object.
+ *
+ * @param graphics The Graphics object to apply the properties to.
+ *
+ * @param targetBounds The bounds of the shape that the stroke is applied to.
+ *
+ * @param targetOrigin The Point that defines the origin (0,0) of the shape in the
+ * coordinate system of target.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function apply(graphics:Graphics, targetBounds:Rectangle, targetOrigin:Point):void;
+
+ /**
+ * Generates a GraphicsStroke object representing
+ * this stroke.
+ *
+ * @param targetBounds The stroke's bounding box.
+ *
+ * @param targetOrigin The Point that defines the origin (0,0) of the shape in the
+ * coordinate system of target.
+ *
+ * @return The Drawing API-2 GraphicsStroke object representing
+ * this stroke.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function createGraphicsStroke(targetBounds:Rectangle, targetOrigin:Point):GraphicsStroke;
+}
+
+}
diff --git a/src/mx/graphics/LinearGradient.as b/src/mx/graphics/LinearGradient.as
new file mode 100644
index 00000000..6d462712
--- /dev/null
+++ b/src/mx/graphics/LinearGradient.as
@@ -0,0 +1,342 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2004-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.graphics
+{
+
+import flash.display.GradientType;
+import flash.display.Graphics;
+import flash.geom.Matrix;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+
+import mx.core.mx_internal;
+
+use namespace mx_internal;
+
+/**
+ * The LinearGradient class lets you specify the fill of a graphical element,
+ * where a gradient specifies a gradual color transition in the fill color.
+ * You add a series of GradientEntry objects
+ * to the LinearGradient object's entries Array
+ * to define the colors that make up the gradient fill.
+ *
+ * In MXML, you define a LinearGradient by adding a series + * of GradientEntry objects, as the following example shows: + *
+ * <mx:fill> + * <mx:LinearGradient> + * <mx:entries> + * <mx:GradientEntry color="0xC5C551" ratio="0.00" alpha="0.5"/> + * <mx:GradientEntry color="0xFEFE24" ratio="0.33" alpha="0.5"/> + * <mx:GradientEntry color="0xECEC21" ratio="0.66" alpha="0.5"/> + * </mx:entries> + * </mx:LinearGradient> + * </mx:fill> + *+ * + * + *
You can also define a LinearGradient as a fill for any graphic element + * in ActionScript, as the following example shows: + *
+ *
+ * <?xml version="1.0"?>
+ * <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()">
+ * <mx:Script>
+ * import flash.display.Graphics;
+ * import flash.geom.Rectangle;
+ * import mx.graphics.GradientEntry;
+ * import mx.graphics.LinearGradient;
+ *
+ * private function init():void
+ * {
+ * var w:Number = 200;
+ * var h:Number = 200;
+ *
+ * var s:Sprite = new Sprite();
+ * // Add the new Sprite to the display list.
+ * rawChildren.addChild(s);
+ *
+ * var g:Graphics = s.graphics;
+ * g.lineStyle(1, 0x33CCFF, 1.0);
+ *
+ * var fill:LinearGradient = new LinearGradient();
+ *
+ * var g1:GradientEntry = new GradientEntry(0xFFCC66, 0.00, 0.5);
+ * var g2:GradientEntry = new GradientEntry(0x000000, 0.33, 0.5);
+ * var g3:GradientEntry = new GradientEntry(0x99FF33, 0.66, 0.5);
+ *
+ * fill.entries = [ g1, g2, g3 ];
+ * fill.angle = 240;
+ *
+ * // Draw a box and fill it with the LinearGradient.
+ * g.moveTo(0, 0);
+ * fill.begin(g, new Rectangle(0, 0, w, h));
+ * g.lineTo(w, 0);
+ * g.lineTo(w, h);
+ * g.lineTo(0, h);
+ * g.lineTo(0, 0);
+ * fill.end(g);
+ * }
+ * </mx:Script>
+ * </mx:Application>
+ *
+ *
+ *
+ * @mxml
+ *
+ * The <mx:LinearGradient> tag
+ * inherits all the tag attributes of its superclass,
+ * and adds the following tag attributes:
+ * <mx:LinearGradient + * Properties + * angle="0" + * /> + *+ * + * @see mx.graphics.GradientEntry + * @see mx.graphics.RadialGradient + * @see mx.graphics.IFill + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class LinearGradient extends GradientBase implements IFill +{ + //include "../core/Version.as"; + + import mx.core.mx_internal; + + /** + * @private + * Version string for this class. + */ + mx_internal static const VERSION:String = "4.1.0.16076"; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function LinearGradient() + { + super(); + } + + /** + * @private + */ + private static var commonMatrix:Matrix = new Matrix(); + + //-------------------------------------------------------------------------- + // + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // matrix + //---------------------------------- + + /** + * @private + */ + override public function set matrix(value:Matrix):void + { + scaleX = NaN; + super.matrix = value; + } + + //---------------------------------- + // scaleX + //---------------------------------- + + private var _scaleX:Number; + + [Bindable("propertyChange")] + [Inspectable(category="General")] + + /** + * The horizontal scale of the gradient transform, which defines the width of the (unrotated) gradient + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get scaleX():Number + { + return compoundTransform ? compoundTransform.scaleX : _scaleX; + } + + /** + * @private + */ + public function set scaleX(value:Number):void + { + if (value != scaleX) + { + var oldValue:Number = scaleX; + + if (compoundTransform) + { + // If we have a compoundTransform, only non-NaN values are allowed + if (!isNaN(value)) + compoundTransform.scaleX = value; + } + else + { + _scaleX = value; + } + dispatchGradientChangedEvent("scaleX", oldValue, value); + } + } + + //-------------------------------------------------------------------------- + // + // + // Methods + // + //-------------------------------------------------------------------------- + + /** + * @inheritDoc + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function begin(target:Graphics, targetBounds:Rectangle, targetOrigin:Point):void + { + commonMatrix.identity(); + + if (!compoundTransform) + { + var tx:Number = x; + var ty:Number = y; + var length:Number = scaleX; + + if (isNaN(length)) + { + // Figure out the two sides + if (rotation % 90 != 0) + { + // Normalize angles with absolute value > 360 + var normalizedAngle:Number = rotation % 360; + // Normalize negative angles + if (normalizedAngle < 0) + normalizedAngle += 360; + + // Angles wrap at 180 + normalizedAngle %= 180; + + // Angles > 90 get mirrored + if (normalizedAngle > 90) + normalizedAngle = 180 - normalizedAngle; + + var side:Number = targetBounds.width; + // Get the hypotenuse of the largest triangle that can fit in the bounds + var hypotenuse:Number = Math.sqrt(targetBounds.width * targetBounds.width + targetBounds.height * targetBounds.height); + // Get the angle of that largest triangle + var hypotenuseAngle:Number = Math.acos(targetBounds.width / hypotenuse) * 180 / Math.PI; + + // If the angle is larger than the hypotenuse angle, then use the height + // as the adjacent side of the triangle + if (normalizedAngle > hypotenuseAngle) + { + normalizedAngle = 90 - normalizedAngle; + side = targetBounds.height; + } + + // Solve for the hypotenuse given an adjacent side and an angle. + length = side / Math.cos(normalizedAngle / 180 * Math.PI); + } + else + { + // Use either width or height based on the rotation + length = (rotation % 180) == 0 ? targetBounds.width : targetBounds.height; + } + } + + // If only x or y is defined, force the other to be set to 0 + if (!isNaN(tx) && isNaN(ty)) + ty = 0; + else if (isNaN(tx) && !isNaN(ty)) + tx = 0; + + // If x and y are specified, then move the gradient so that the + // top left corner is at 0,0 + if (!isNaN(tx) && !isNaN(ty)) + commonMatrix.translate(GRADIENT_DIMENSION / 2, GRADIENT_DIMENSION / 2); // 1638.4 / 2 + + // Force the length to a absolute minimum of 2. Values of 0, 1, or -1 have undesired behavior + if (length >= 0 && length < 2) + length = 2; + else if (length < 0 && length > -2) + length = -2; + + // Scale the gradient in the x direction. The natural size is 1638.4px. No need + // to scale the y direction because it is infinite + commonMatrix.scale (length / GRADIENT_DIMENSION, 1 / GRADIENT_DIMENSION); + + commonMatrix.rotate (!isNaN(_angle) ? _angle : rotationInRadians); + if (isNaN(tx)) + tx = targetBounds.left + targetBounds.width / 2; + else + tx += targetOrigin.x; + if (isNaN(ty)) + ty = targetBounds.top + targetBounds.height / 2; + else + ty += targetOrigin.y; + commonMatrix.translate(tx, ty); + } + else + { + commonMatrix.translate(GRADIENT_DIMENSION / 2, GRADIENT_DIMENSION / 2); + commonMatrix.scale(1 / GRADIENT_DIMENSION, 1 / GRADIENT_DIMENSION); + commonMatrix.concat(compoundTransform.matrix); + commonMatrix.translate(targetOrigin.x, targetOrigin.y); + } + + target.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, + commonMatrix, spreadMethod, interpolationMethod); + } + + /** + * @inheritDoc + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function end(target:Graphics):void + { + target.endFill(); + } +} + +} diff --git a/src/mx/graphics/LinearGradientStroke.as b/src/mx/graphics/LinearGradientStroke.as new file mode 100644 index 00000000..0361990f --- /dev/null +++ b/src/mx/graphics/LinearGradientStroke.as @@ -0,0 +1,346 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2005-2007 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.graphics +{ + +import flash.display.GradientType; +import flash.display.Graphics; +import flash.display.GraphicsGradientFill; +import flash.display.GraphicsStroke; +import flash.geom.Matrix; +import flash.geom.Point; +import flash.geom.Rectangle; + +import mx.core.mx_internal; + +use namespace mx_internal; + +/** + * The LinearGradientStroke class lets you specify a gradient filled stroke. + * You use the LinearGradientStroke class, along with the GradientEntry class, + * to define a gradient stroke. + * + * @see mx.graphics.Stroke + * @see mx.graphics.GradientEntry + * @see mx.graphics.RadialGradient + * @see flash.display.Graphics + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class LinearGradientStroke extends GradientStroke +{ + //include "../core/Version.as"; + + import mx.core.mx_internal; + + /** + * @private + * Version string for this class. + */ + mx_internal static const VERSION:String = "4.1.0.16076"; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @param weight Specifies the line weight, in pixels. + * This parameter is optional, + * with a default value of
1.
+ *
+ * @param pixelHinting A Boolean value that specifies
+ * whether to hint strokes to full pixels.
+ * This affects both the position of anchors of a curve
+ * and the line stroke size itself.
+ * With pixelHinting set to true,
+ * Flash Player and AIR hint line widths to full pixel widths.
+ * With pixelHinting set to false,
+ * disjoints can appear for curves and straight lines.
+ * This parameter is optional,
+ * with a default value of false.
+ *
+ * @param scaleMode A value from the LineScaleMode class
+ * that specifies which scale mode to use.
+ * Valid values are LineScaleMode.HORIZONTAL,
+ * LineScaleMode.NONE, LineScaleMode.NORMAL,
+ * and LineScaleMode.VERTICAL.
+ * This parameter is optional,
+ * with a default value of LineScaleMode.NONE.
+ *
+ * @param caps A value from the CapsStyle class
+ * that specifies the type of caps at the end of lines.
+ * Valid values are CapsStyle.NONE,
+ * CapsStyle.ROUND, and CapsStyle.SQUARE.
+ * A null value is equivalent to
+ * CapsStyle.ROUND.
+ * This parameter is optional,
+ * with a default value of CapsStyle.ROUND.
+ *
+ * @param joints A value from the JointStyle class
+ * that specifies the type of joint appearance used at angles.
+ * Valid values are JointStyle.BEVEL,
+ * JointStyle.MITER, and JointStyle.ROUND.
+ * A null value is equivalent to
+ * JointStyle.ROUND.
+ * This parameter is optional,
+ * with a default value of JointStyle.ROUND.
+ *
+ * @param miterLimit A number that indicates the limit
+ * at which a miter is cut off.
+ * Valid values range from 1 to 255
+ * (and values outside of that range are rounded to 1 or 255).
+ * This value is only used if the jointStyle property
+ * is set to miter.
+ * The miterLimit value represents the length that a miter
+ * can extend beyond the point at which the lines meet to form a joint.
+ * The value expresses a factor of the line thickness.
+ * For example, with a miterLimit factor of 2.5 and a
+ * thickness of 10 pixels, the miter is cut off at 25 pixels.
+ * This parameter is optional,
+ * with a default value of 3.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function LinearGradientStroke(weight:Number = 1,
+ pixelHinting:Boolean = false,
+ scaleMode:String = "normal",
+ caps:String = "round",
+ joints:String = "round",
+ miterLimit:Number = 3)
+ {
+ super(weight, pixelHinting, scaleMode, caps, joints, miterLimit);
+ }
+
+ /**
+ * @private
+ */
+ private static var commonMatrix:Matrix = new Matrix();
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // matrix
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function set matrix(value:Matrix):void
+ {
+ scaleX = NaN;
+ super.matrix = value;
+ }
+
+ //----------------------------------
+ // scaleX
+ //----------------------------------
+
+ private var _scaleX:Number;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * The horizontal scale of the gradient transform, which defines the width of the (unrotated) gradient
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get scaleX():Number
+ {
+ return compoundTransform ? compoundTransform.scaleX : _scaleX;
+ }
+
+ /**
+ * @private
+ */
+ public function set scaleX(value:Number):void
+ {
+ if (value != scaleX)
+ {
+ var oldValue:Number = scaleX;
+
+ if (compoundTransform)
+ {
+ // If we have a compoundTransform, only non-NaN values are allowed
+ if (!isNaN(value))
+ compoundTransform.scaleX = value;
+ }
+ else
+ {
+ _scaleX = value;
+ }
+ dispatchGradientChangedEvent("scaleX", oldValue, value);
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @inheritDoc
+ */
+ override public function apply(graphics:Graphics, targetBounds:Rectangle, targetOrigin:Point):void
+ {
+ commonMatrix.identity();
+
+ graphics.lineStyle(weight, 0, 1, pixelHinting, scaleMode,
+ caps, joints, miterLimit);
+
+ if (targetBounds)
+ calculateTransformationMatrix(targetBounds, commonMatrix, targetOrigin);
+
+ graphics.lineGradientStyle(GradientType.LINEAR, colors,
+ alphas, ratios,
+ commonMatrix, spreadMethod,
+ interpolationMethod);
+ }
+
+ /**
+ * @private
+ */
+ override public function createGraphicsStroke(targetBounds:Rectangle, targetOrigin:Point):GraphicsStroke
+ {
+ // The parent class sets the gradient stroke properties common to
+ // LinearGradientStroke and RadialGradientStroke
+ var graphicsStroke:GraphicsStroke = super.createGraphicsStroke(targetBounds, targetOrigin);
+
+ if (graphicsStroke)
+ {
+ // Set other properties specific to this LinearGradientStroke
+ GraphicsGradientFill(graphicsStroke.fill).type = GradientType.LINEAR;
+ calculateTransformationMatrix(targetBounds, commonMatrix, targetOrigin);
+ GraphicsGradientFill(graphicsStroke.fill).matrix = commonMatrix;
+ }
+
+ return graphicsStroke;
+ }
+
+ /**
+ * @private
+ * Calculates this LinearGradientStroke's transformation matrix.
+ */
+ private function calculateTransformationMatrix(targetBounds:Rectangle, matrix:Matrix, targetOrigin:Point):void
+ {
+ matrix.identity();
+
+ if (!compoundTransform)
+ {
+ var tx:Number = x;
+ var ty:Number = y;
+ var length:Number = scaleX;
+
+ if (isNaN(length))
+ {
+ // Figure out the two sides
+ if (rotation % 90 != 0)
+ {
+ // Normalize angles with absolute value > 360
+ var normalizedAngle:Number = rotation % 360;
+ // Normalize negative angles
+ if (normalizedAngle < 0)
+ normalizedAngle += 360;
+
+ // Angles wrap at 180
+ normalizedAngle %= 180;
+
+ // Angles > 90 get mirrored
+ if (normalizedAngle > 90)
+ normalizedAngle = 180 - normalizedAngle;
+
+ var side:Number = targetBounds.width;
+ // Get the hypotenuse of the largest triangle that can fit in the bounds
+ var hypotenuse:Number = Math.sqrt(targetBounds.width * targetBounds.width + targetBounds.height * targetBounds.height);
+ // Get the angle of that largest triangle
+ var hypotenuseAngle:Number = Math.acos(targetBounds.width / hypotenuse) * 180 / Math.PI;
+
+ // If the angle is larger than the hypotenuse angle, then use the height
+ // as the adjacent side of the triangle
+ if (normalizedAngle > hypotenuseAngle)
+ {
+ normalizedAngle = 90 - normalizedAngle;
+ side = targetBounds.height;
+ }
+
+ // Solve for the hypotenuse given an adjacent side and an angle.
+ length = side / Math.cos(normalizedAngle / 180 * Math.PI);
+ }
+ else
+ {
+ // Use either width or height based on the rotation
+ length = (rotation % 180) == 0 ? targetBounds.width : targetBounds.height;
+ }
+ }
+
+ // If only x or y is defined, force the other to be set to 0
+ if (!isNaN(tx) && isNaN(ty))
+ ty = 0;
+ else if (isNaN(tx) && !isNaN(ty))
+ tx = 0;
+
+ // If x and y are specified, then move the gradient so that the
+ // top left corner is at 0,0
+ if (!isNaN(tx) && !isNaN(ty))
+ matrix.translate(GRADIENT_DIMENSION / 2, GRADIENT_DIMENSION / 2); // 1638.4 / 2
+
+ // Force the length to a absolute minimum of 2. Values of 0, 1, or -1 have undesired behavior
+ if (length >= 0 && length < 2)
+ length = 2;
+ else if (length < 0 && length > -2)
+ length = -2;
+
+ // Scale the gradient in the x direction. The natural size is 1638.4px. No need
+ // to scale the y direction because it is infinite
+ matrix.scale (length / GRADIENT_DIMENSION, 1 / GRADIENT_DIMENSION);
+
+ matrix.rotate (!isNaN(_angle) ? _angle : rotationInRadians);
+ if (isNaN(tx))
+ tx = targetBounds.left + targetBounds.width / 2;
+ else
+ tx += targetOrigin.x;
+ if (isNaN(ty))
+ ty = targetBounds.top + targetBounds.height / 2;
+ else
+ ty += targetOrigin.y;
+ matrix.translate(tx, ty);
+ }
+ else
+ {
+ matrix.translate(GRADIENT_DIMENSION / 2, GRADIENT_DIMENSION / 2);
+ matrix.scale(1 / GRADIENT_DIMENSION, 1 / GRADIENT_DIMENSION);
+ matrix.concat(compoundTransform.matrix);
+ matrix.translate(targetOrigin.x, targetOrigin.y);
+ }
+ }
+
+}
+
+}
diff --git a/src/mx/graphics/RadialGradient.as b/src/mx/graphics/RadialGradient.as
new file mode 100644
index 00000000..2c2840d1
--- /dev/null
+++ b/src/mx/graphics/RadialGradient.as
@@ -0,0 +1,385 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2004-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.graphics
+{
+
+import flash.display.GradientType;
+import flash.display.Graphics;
+import flash.geom.Matrix;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+
+import mx.core.mx_internal;
+
+use namespace mx_internal;
+
+/**
+ * The RadialGradient class lets you specify a gradual color transition
+ * in the fill color.
+ * A radial gradient defines a fill pattern
+ * that radiates out from the center of a graphical element.
+ * You add a series of GradientEntry objects
+ * to the RadialGradient object's entries Array
+ * to define the colors that make up the gradient fill.
+ *
+ * In MXML, you define a RadialGradient by adding a series + * of GradientEntry objects, as the following example shows: + *
+ * <mx:fill> + * <mx:RadialGradient> + * <mx:entries> + * <mx:GradientEntry color="0xC5C551" ratio="0.00" alpha="0.5"/> + * <mx:GradientEntry color="0xFEFE24" ratio="0.33" alpha="0.5"/> + * <mx:GradientEntry color="0xECEC21" ratio="0.66" alpha="0.5"/> + * </mx:entries> + * </mx:RadialGradient> + * </mx:fill> + *+ * + * + *
You can also define a RadialGradient as a fill for any graphic element + * in ActionScript, as the following example shows: + *
+ *
+ * <?xml version="1.0"?>
+ * <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()">
+ * <mx:Script>
+ * import flash.display.Graphics;
+ * import flash.geom.Rectangle;
+ * import mx.graphics.GradientEntry;
+ * import mx.graphics.RadialGradient;
+ *
+ * private function init():void
+ * {
+ * var w:Number = 200;
+ * var h:Number = 200;
+ *
+ * var s:Sprite = new Sprite();
+ * // Add the new Sprite to the display list.
+ * rawChildren.addChild(s);
+ *
+ * var g:Graphics = s.graphics;
+ * g.lineStyle(1, 0x33CCFF, 1.0);
+ *
+ * var fill:RadialGradient = new RadialGradient();
+ *
+ * var g1:GradientEntry = new GradientEntry(0xFFCC66, 0.00, 0.5);
+ * var g2:GradientEntry = new GradientEntry(0x000000, 0.33, 0.5);
+ * var g3:GradientEntry = new GradientEntry(0x99FF33, 0.66, 0.5);
+ *
+ * fill.entries = [ g1, g2, g3 ];
+ *
+ * // Set focal point to upper left corner.
+ * fill.angle = 45;
+ * fill.focalPointRatio = -0.8;
+ *
+ * // Draw a box and fill it with the RadialGradient.
+ * g.moveTo(0, 0);
+ * fill.begin(g,new Rectangle(0, 0, w, h));
+ * g.lineTo(w, 0);
+ * g.lineTo(w, h);
+ * g.lineTo(0, h);
+ * g.lineTo(0, 0);
+ * fill.end(g);
+ * }
+ * </mx:Script>
+ * </mx:Application>
+ *
+ *
+ *
+ * @mxml
+ *
+ * The <mx:RadialGradient> tag
+ * inherits all the tag attributes of its superclass,
+ * and adds the following tag attributes:
+ * <mx:RadialGradient + * Properties + * angle="0" + * focalPointRatio="0" + * /> + *+ * + * @see mx.graphics.GradientEntry + * @see mx.graphics.LinearGradient + * @see mx.graphics.IFill + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class RadialGradient extends GradientBase implements IFill +{ + //include "../core/Version.as"; + + import mx.core.mx_internal; + + /** + * @private + * Version string for this class. + */ + mx_internal static const VERSION:String = "4.1.0.16076"; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function RadialGradient() + { + super(); + } + + /** + * @private + */ + private static var commonMatrix:Matrix = new Matrix(); + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // focalPointRatio + //---------------------------------- + + /** + * @private + * Storage for the focalPointRatio property. + */ + private var _focalPointRatio:Number = 0.0; + + [Bindable("propertyChange")] + [Inspectable(category="General")] + + /** + * Sets the location of the start of the radial fill. + * + *
Valid values are from -1.0 to 1.0.
+ * A value of -1.0 sets the focal point
+ * (or, start of the gradient fill)
+ * on the left of the bounding Rectangle.
+ * A value of 1.0 sets the focal point
+ * on the right of the bounding Rectangle.
+ *
+ *
If you use this property in conjunction
+ * with the angle property,
+ * this value specifies the degree of distance
+ * from the center that the focal point occurs.
+ * For example, with an angle of 45
+ * and focalPointRatio of 0.25,
+ * the focal point is slightly lower and to the right of center.
+ * If you set focalPointRatio to 0,
+ * the focal point is in the middle of the bounding Rectangle.
focalPointRatio to 1,
+ * the focal point is all the way to the bottom right corner
+ * of the bounding Rectangle.
+ *
+ * @default 0.0
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get focalPointRatio():Number
+ {
+ return _focalPointRatio;
+ }
+
+ /**
+ * @private
+ */
+ public function set focalPointRatio(value:Number):void
+ {
+ var oldValue:Number = _focalPointRatio;
+ if (value != oldValue)
+ {
+ _focalPointRatio = value;
+
+ dispatchGradientChangedEvent("focalPointRatio", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // matrix
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function set matrix(value:Matrix):void
+ {
+ scaleX = NaN;
+ scaleY = NaN;
+ super.matrix = value;
+ }
+
+ //----------------------------------
+ // scaleX
+ //----------------------------------
+
+ private var _scaleX:Number;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * The horizontal scale of the gradient transform, which defines the width of the (unrotated) gradient
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get scaleX():Number
+ {
+ return compoundTransform ? compoundTransform.scaleX : _scaleX;
+ }
+
+ /**
+ * @private
+ */
+ public function set scaleX(value:Number):void
+ {
+ if (value != scaleX)
+ {
+ var oldValue:Number = scaleX;
+
+ if (compoundTransform)
+ {
+ // If we have a compoundTransform, only non-NaN values are allowed
+ if (!isNaN(value))
+ compoundTransform.scaleX = value;
+ }
+ else
+ {
+ _scaleX = value;
+ }
+ dispatchGradientChangedEvent("scaleX", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // scaleY
+ //----------------------------------
+
+ private var _scaleY:Number;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * The vertical scale of the gradient transform, which defines the height of the (unrotated) gradient
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get scaleY():Number
+ {
+ return compoundTransform ? compoundTransform.scaleY : _scaleY;
+ }
+
+ /**
+ * @private
+ */
+ public function set scaleY(value:Number):void
+ {
+ if (value != scaleY)
+ {
+ var oldValue:Number = scaleY;
+
+ if (compoundTransform)
+ {
+ // If we have a compoundTransform, only non-NaN values are allowed
+ if (!isNaN(value))
+ compoundTransform.scaleY = value;
+ }
+ else
+ {
+ _scaleY = value;
+ }
+ dispatchGradientChangedEvent("scaleY", oldValue, value);
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function begin(target:Graphics, targetBounds:Rectangle, targetOrigin:Point):void
+ {
+ var w:Number = !isNaN(scaleX) ? scaleX : targetBounds.width;
+ var h:Number = !isNaN(scaleY) ? scaleY : targetBounds.height;
+ var regX:Number = !isNaN(x) ? x + targetOrigin.x : targetBounds.left + targetBounds.width / 2;
+ var regY:Number = !isNaN(y) ? y + targetOrigin.y : targetBounds.top + targetBounds.height / 2;
+
+ commonMatrix.identity();
+
+ if (!compoundTransform)
+ {
+ commonMatrix.scale (w / GRADIENT_DIMENSION, h / GRADIENT_DIMENSION);
+ commonMatrix.rotate(!isNaN(_angle) ? _angle : rotationInRadians);
+ commonMatrix.translate(regX, regY);
+ }
+ else
+ {
+ commonMatrix.scale(1 / GRADIENT_DIMENSION, 1 / GRADIENT_DIMENSION);
+ commonMatrix.concat(compoundTransform.matrix);
+ commonMatrix.translate(targetOrigin.x, targetOrigin.y);
+ }
+
+ target.beginGradientFill(GradientType.RADIAL, colors, alphas, ratios,
+ commonMatrix, spreadMethod, interpolationMethod, focalPointRatio);
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function end(target:Graphics):void
+ {
+ target.endFill();
+ }
+
+}
+
+}
diff --git a/src/mx/graphics/RadialGradientStroke.as b/src/mx/graphics/RadialGradientStroke.as
new file mode 100644
index 00000000..cf8f9cf9
--- /dev/null
+++ b/src/mx/graphics/RadialGradientStroke.as
@@ -0,0 +1,365 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.graphics
+{
+
+import flash.display.GradientType;
+import flash.display.Graphics;
+import flash.display.GraphicsGradientFill;
+import flash.display.GraphicsStroke;
+import flash.geom.Matrix;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+
+import mx.core.mx_internal;
+
+use namespace mx_internal;
+
+/**
+ * The RadialGradientStroke class lets you specify a gradient filled stroke.
+ * You use the RadialGradientStroke class, along with the GradientEntry class,
+ * to define a gradient stroke.
+ *
+ * @see mx.graphics.Stroke
+ * @see mx.graphics.GradientEntry
+ * @see mx.graphics.RadialGradient
+ * @see flash.display.Graphics
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class RadialGradientStroke extends GradientStroke
+{
+ /**
+ * Constructor.
+ *
+ * @param weight Specifies the line weight, in pixels.
+ * This parameter is optional,
+ * with a default value of 1.
+ *
+ * @param pixelHinting A Boolean value that specifies
+ * whether to hint strokes to full pixels.
+ * This affects both the position of anchors of a curve
+ * and the line stroke size itself.
+ * With pixelHinting set to true,
+ * Flash Player and AIR hint line widths to full pixel widths.
+ * With pixelHinting set to false,
+ * disjoints can appear for curves and straight lines.
+ * This parameter is optional,
+ * with a default value of false.
+ *
+ * @param scaleMode A value from the LineScaleMode class
+ * that specifies which scale mode to use.
+ * Valid values are LineScaleMode.HORIZONTAL,
+ * LineScaleMode.NONE, LineScaleMode.NORMAL,
+ * and LineScaleMode.VERTICAL.
+ * This parameter is optional,
+ * with a default value of LineScaleMode.NORMAL.
+ *
+ * @param caps A value from the CapsStyle class
+ * that specifies the type of caps at the end of lines.
+ * Valid values are CapsStyle.NONE,
+ * CapsStyle.ROUND, and CapsStyle.SQUARE.
+ * A null value is equivalent to
+ * CapsStyle.ROUND.
+ * This parameter is optional,
+ * with a default value of CapsStyle.ROUND.
+ *
+ * @param joints A value from the JointStyle class
+ * that specifies the type of joint appearance used at angles.
+ * Valid values are JointStyle.BEVEL,
+ * JointStyle.MITER, and JointStyle.ROUND.
+ * A null value is equivalent to
+ * JointStyle.ROUND.
+ * This parameter is optional,
+ * with a default value of JointStyle.ROUND.
+ *
+ * @param miterLimit A number that indicates the limit
+ * at which a miter is cut off.
+ * Valid values range from 1 to 255
+ * (and values outside of that range are rounded to 1 or 255).
+ * This value is only used if the jointStyle property
+ * is set to miter.
+ * The miterLimit value represents the length that a miter
+ * can extend beyond the point at which the lines meet to form a joint.
+ * The value expresses a factor of the line thickness.
+ * For example, with a miterLimit factor of 2.5 and a
+ * thickness of 10 pixels, the miter is cut off at 25 pixels.
+ * This parameter is optional,
+ * with a default value of 3.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function RadialGradientStroke(weight:Number = 1,
+ pixelHinting:Boolean = false,
+ scaleMode:String = "normal",
+ caps:String = "round",
+ joints:String = "round",
+ miterLimit:Number = 3)
+ {
+ super(weight, pixelHinting, scaleMode, caps, joints, miterLimit);
+ }
+
+ /**
+ * @private
+ */
+ private static var commonMatrix:Matrix = new Matrix();
+
+ //----------------------------------
+ // focalPointRatio
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the focalPointRatio property.
+ */
+ private var _focalPointRatio:Number = 0.0;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * Sets the location of the start of the radial fill.
+ *
+ * Valid values are from -1.0 to 1.0.
+ * A value of -1.0 sets the focal point
+ * (or, start of the gradient fill)
+ * on the left of the bounding Rectangle.
+ * A value of 1.0 sets the focal point
+ * on the right of the bounding Rectangle.
+ *
+ *
If you use this property in conjunction
+ * with the angle property,
+ * this value specifies the degree of distance
+ * from the center that the focal point occurs.
+ * For example, with an angle of 45
+ * and focalPointRatio of 0.25,
+ * the focal point is slightly lower and to the right of center.
+ * If you set focalPointRatio to 0,
+ * the focal point is in the middle of the bounding Rectangle.
focalPointRatio to 1,
+ * the focal point is all the way to the bottom right corner
+ * of the bounding Rectangle.
+ *
+ * @default 0.0
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get focalPointRatio():Number
+ {
+ return _focalPointRatio;
+ }
+
+ /**
+ * @private
+ */
+ public function set focalPointRatio(value:Number):void
+ {
+ var oldValue:Number = _focalPointRatio;
+ if (value != oldValue)
+ {
+ _focalPointRatio = value;
+
+ dispatchGradientChangedEvent("focalPointRatio",
+ oldValue, value);
+ }
+ }
+
+ //----------------------------------
+
+ // matrix
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ override public function set matrix(value:Matrix):void
+ {
+ scaleX = NaN;
+ scaleY = NaN;
+ super.matrix = value;
+ }
+
+ //----------------------------------
+ // scaleX
+ //----------------------------------
+
+ private var _scaleX:Number;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * The horizontal scale of the gradient transform, which defines the width of the (unrotated) gradient
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get scaleX():Number
+ {
+ return compoundTransform ? compoundTransform.scaleX : _scaleX;
+ }
+
+ /**
+ * @private
+ */
+ public function set scaleX(value:Number):void
+ {
+ if (value != scaleX)
+ {
+ var oldValue:Number = scaleX;
+
+ if (compoundTransform)
+ {
+ // If we have a compoundTransform, only non-NaN values are allowed
+ if (!isNaN(value))
+ compoundTransform.scaleX = value;
+ }
+ else
+ {
+ _scaleX = value;
+ }
+ dispatchGradientChangedEvent("scaleX", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // scaleY
+ //----------------------------------
+
+ private var _scaleY:Number;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * The vertical scale of the gradient transform, which defines the height of the (unrotated) gradient
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get scaleY():Number
+ {
+ return compoundTransform ? compoundTransform.scaleY : _scaleY;
+ }
+
+ /**
+ * @private
+ */
+ public function set scaleY(value:Number):void
+ {
+ if (value != scaleY)
+ {
+ var oldValue:Number = scaleY;
+
+ if (compoundTransform)
+ {
+ // If we have a compoundTransform, only non-NaN values are allowed
+ if (!isNaN(value))
+ compoundTransform.scaleY = value;
+ }
+ else
+ {
+ _scaleY = value;
+ }
+ dispatchGradientChangedEvent("scaleY", oldValue, value);
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override public function apply(graphics:Graphics, targetBounds:Rectangle, targetOrigin:Point):void
+ {
+ commonMatrix.identity();
+
+ graphics.lineStyle(weight, 0, 1, pixelHinting, scaleMode,
+ caps, joints, miterLimit);
+
+ if (targetBounds)
+ calculateTransformationMatrix(targetBounds, commonMatrix, targetOrigin);
+
+ graphics.lineGradientStyle(GradientType.RADIAL, colors,
+ alphas, ratios, commonMatrix,
+ spreadMethod, interpolationMethod,
+ focalPointRatio);
+ }
+
+ /**
+ * @private
+ */
+ override public function createGraphicsStroke(targetBounds:Rectangle, targetOrigin:Point):GraphicsStroke
+ {
+ // The parent class sets the gradient stroke properties common to
+ // LinearGradientStroke and RadialGradientStroke
+ var graphicsStroke:GraphicsStroke = super.createGraphicsStroke(targetBounds, targetOrigin);
+
+ if (graphicsStroke)
+ {
+ // Set other properties specific to this RadialGradientStroke
+ GraphicsGradientFill(graphicsStroke.fill).type = GradientType.RADIAL;
+ calculateTransformationMatrix(targetBounds, commonMatrix, targetOrigin);
+ GraphicsGradientFill(graphicsStroke.fill).matrix = commonMatrix;
+ GraphicsGradientFill(graphicsStroke.fill).focalPointRatio = focalPointRatio;
+
+ }
+
+ return graphicsStroke;
+ }
+
+ /**
+ * @private
+ * Calculates this RadialGradientStroke's transformation matrix
+ */
+ private function calculateTransformationMatrix(targetBounds:Rectangle, matrix:Matrix, targetOrigin:Point):void
+ {
+ matrix.identity();
+
+ if (!compoundTransform)
+ {
+ var w:Number = !isNaN(scaleX) ? scaleX : targetBounds.width;
+ var h:Number = !isNaN(scaleY) ? scaleY : targetBounds.height;
+ var regX:Number = !isNaN(x) ? x + targetOrigin.x : targetBounds.left + targetBounds.width / 2;
+ var regY:Number = !isNaN(y) ? y + targetOrigin.y : targetBounds.top + targetBounds.height / 2;
+
+ matrix.scale (w / GRADIENT_DIMENSION, h / GRADIENT_DIMENSION);
+ matrix.rotate(!isNaN(_angle) ? _angle : rotationInRadians);
+ matrix.translate(regX, regY);
+ }
+ else
+ {
+ matrix.scale(1 / GRADIENT_DIMENSION, 1 / GRADIENT_DIMENSION);
+ matrix.concat(compoundTransform.matrix);
+ matrix.translate(targetOrigin.x, targetOrigin.y);
+ }
+ }
+
+}
+}
diff --git a/src/mx/graphics/SolidColor.as b/src/mx/graphics/SolidColor.as
new file mode 100644
index 00000000..1db5fb27
--- /dev/null
+++ b/src/mx/graphics/SolidColor.as
@@ -0,0 +1,194 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2004-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.graphics
+{
+
+import flash.display.Graphics;
+import flash.events.EventDispatcher;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+
+import mx.events.PropertyChangeEvent;
+
+[DefaultProperty("color")]
+
+/**
+ * Defines a representation for a color,
+ * including a color and an alpha value.
+ *
+ * @see mx.graphics.IFill
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class SolidColor extends EventDispatcher implements IFill
+{
+ //include "../core/Version.as";
+
+ import mx.core.mx_internal;
+
+ /**
+ * @private
+ * Version string for this class.
+ */
+ mx_internal static const VERSION:String = "4.1.0.16076";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param color Specifies the color.
+ * The default value is 0x000000 (black).
+ *
+ * @param alpha Specifies the level of transparency.
+ * Valid values range from 0.0 (completely transparent)
+ * to 1.0 (completely opaque).
+ * The default value is 1.0.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function SolidColor(color:uint = 0x000000, alpha:Number = 1.0)
+ {
+ super();
+
+ this.color = color;
+ this.alpha = alpha;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // alpha
+ //----------------------------------
+
+ private var _alpha:Number = 1.0;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General", minValue="0.0", maxValue="1.0")]
+
+ /**
+ * The transparency of a color.
+ * Possible values are 0.0 (invisible) through 1.0 (opaque).
+ *
+ * @default 1.0
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get alpha():Number
+ {
+ return _alpha;
+ }
+
+ public function set alpha(value:Number):void
+ {
+ var oldValue:Number = _alpha;
+ if (value != oldValue)
+ {
+ _alpha = value;
+ dispatchFillChangedEvent("alpha", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // color
+ //----------------------------------
+
+ private var _color:uint = 0x000000;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General", format="Color")]
+
+ /**
+ * A color value.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get color():uint
+ {
+ return _color;
+ }
+
+ public function set color(value:uint):void
+ {
+ var oldValue:uint = _color;
+ if (value != oldValue)
+ {
+ _color = value;
+ dispatchFillChangedEvent("color", oldValue, value);
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function begin(target:Graphics, targetBounds:Rectangle, targetOrigin:Point):void
+ {
+ target.beginFill(color, alpha);
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function end(target:Graphics):void
+ {
+ target.endFill();
+ }
+
+ /**
+ * @private
+ */
+ private function dispatchFillChangedEvent(prop:String, oldValue:*,
+ value:*):void
+ {
+ if (hasEventListener("propertyChange"))
+ dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, prop,
+ oldValue, value));
+ }
+}
+
+}
diff --git a/src/mx/graphics/SolidColorStroke.as b/src/mx/graphics/SolidColorStroke.as
new file mode 100644
index 00000000..c4a4116c
--- /dev/null
+++ b/src/mx/graphics/SolidColorStroke.as
@@ -0,0 +1,537 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2004-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.graphics
+{
+
+import flash.display.CapsStyle;
+import flash.display.Graphics;
+import flash.display.GraphicsSolidFill;
+import flash.display.GraphicsStroke;
+import flash.display.JointStyle;
+import flash.events.EventDispatcher;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+
+import mx.events.PropertyChangeEvent;
+
+/**
+ * The SolidColorStroke class defines the properties for a line.
+ *
+ * You can define a SolidColorStroke object in MXML, but you must attach that SolidColorStroke to
+ * another object for it to appear in your application. The following example
+ * defines two SolidColorStroke objects and then uses them in the horizontalAxisRenderer
+ * of a LineChart control:
+ *
+ *
+ * ...
+ * <mx:SolidColorStroke id="ticks" color="0xFF0000" weight="1"/>
+ * <mx:SolidColorStroke id="mticks" color="0x0000FF" weight="1"/>
+ *
+ * <mx:LineChart id="mychart" dataProvider="{ndxa}">
+ * <mx:horizontalAxisRenderer>
+ * <mx:AxisRenderer placement="bottom" canDropLabels="true">
+ * <mx:tickStroke>{ticks}</mx:tickStroke>
+ * <mx:minorTickStroke>{mticks}</mx:minorTickStroke>
+ * </mx:AxisRenderer>
+ * </mx:horizontalAxisRenderer>
+ * </LineChart>
+ * ...
+ *
+ *
+ * @mxml
+ *
+ * The <mx:SolidColorStroke> tag inherits all the tag attributes
+ * of its superclass, and adds the following tag attributes:
+ * <mx:SolidColorStroke + * Properties + * alpha="1.0" + * caps="round|none|square" + * color="0x000000" + * joints="round|bevel|miter" + * miterLimit="3" + * pixelHinting="false|true" + * scaleMode="normal|none|horizontal|vertical" + * weight="1 (in most cases)" + * /> + *+ * + * @see flash.display.Graphics + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class SolidColorStroke extends EventDispatcher implements IStroke +{ + //include "../core/Version.as"; + + import mx.core.mx_internal; + + /** + * @private + * Version string for this class. + */ + mx_internal static const VERSION:String = "4.1.0.16076"; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @param color Specifies the line color. + * The default value is 0x000000 (black). + * + * @param weight Specifies the line weight, in pixels. + * The default value is 1. + * + * @param alpha Specifies the alpha value in the range 0.0 to 1.0. + * The default value is 1.0 (opaque). + * + * @param pixelHinting Specifies whether to hint strokes to full pixels. + * This value affects both the position of anchors of a curve + * and the line stroke size itself. + * The default value is false. + * + * @param scaleMode A value from the LineScaleMode class + * that specifies which scale mode to use. + * Valid values are
LineScaleMode.HORIZONTAL,
+ * LineScaleMode.NONE, LineScaleMode.NORMAL,
+ * and LineScaleMode.VERTICAL.
+ * This parameter is optional,
+ * with a default value of LineScaleMode.NORMAL.
+ *
+ * @param caps Specifies the type of caps at the end of lines.
+ * Valid values are CapsStyle.ROUND, CapsStyle.SQUARE,
+ * and CapsStyle.NONE.
+ * The default value is CapsStyle.ROUND.
+ *
+ * @param joints Specifies the type of joint appearance used at angles.
+ * Valid values are JointStyle.ROUND, JointStyle.MITER,
+ * and JointStyle.BEVEL.
+ * The default value is JointStyle.ROUND.
+ *
+ * @param miterLimit Indicates the limit at which a miter is cut off.
+ * Valid values range from 0 to 255.
+ * The default value is 3.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function SolidColorStroke(color:uint = 0x000000,
+ weight:Number = 1,
+ alpha:Number = 1.0,
+ pixelHinting:Boolean = false,
+ scaleMode:String = "normal",
+ caps:String = "round",
+ joints:String = "round",
+ miterLimit:Number = 3)
+ {
+ super();
+
+ this.color = color;
+ this._weight = weight;
+ this.alpha = alpha;
+ this.pixelHinting = pixelHinting;
+ this.scaleMode = scaleMode;
+ this.caps = caps;
+ this.joints = joints;
+ this.miterLimit = miterLimit;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // alpha
+ //----------------------------------
+
+ private var _alpha:Number = 0.0;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * The transparency of a line.
+ * Possible values are 0.0 (invisible) through 1.0 (opaque).
+ *
+ * @default 1.0.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get alpha():Number
+ {
+ return _alpha;
+ }
+
+ /**
+ * @private
+ */
+ public function set alpha(value:Number):void
+ {
+ var oldValue:Number = _alpha;
+ if (value != oldValue)
+ {
+ _alpha = value;
+ dispatchStrokeChangedEvent("alpha", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // caps
+ //----------------------------------
+
+ private var _caps:String = CapsStyle.ROUND;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General", enumeration="round,square,none", defaultValue="round")]
+
+ /**
+ * Specifies the type of caps at the end of lines.
+ * Valid values are: CapsStyle.ROUND, CapsStyle.SQUARE,
+ * and CapsStyle.NONE.
+ *
+ * @default CapsStyle.ROUND
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get caps():String
+ {
+ return _caps;
+ }
+
+ public function set caps(value:String):void
+ {
+ var oldValue:String = _caps;
+ if (value != oldValue)
+ {
+ _caps = value;
+ dispatchStrokeChangedEvent("caps", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // color
+ //----------------------------------
+
+ private var _color:uint = 0x000000;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General", format="Color")]
+
+ /**
+ * The line color.
+ *
+ * @default 0x000000 (black).
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get color():uint
+ {
+ return _color;
+ }
+
+ public function set color(value:uint):void
+ {
+ var oldValue:uint = _color;
+ if (value != oldValue)
+ {
+ _color = value;
+ dispatchStrokeChangedEvent("color", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // joints
+ //----------------------------------
+
+ private var _joints:String = JointStyle.ROUND;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General", enumeration="round,bevel,miter", defaultValue="round")]
+
+ /**
+ * Specifies the type of joint appearance used at angles.
+ * Valid values are JointStyle.ROUND, JointStyle.MITER,
+ * and JointStyle.BEVEL.
+ *
+ * @default JointStyle.ROUND
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get joints():String
+ {
+ return _joints;
+ }
+
+ public function set joints(value:String):void
+ {
+ var oldValue:String = _joints;
+ if (value != oldValue)
+ {
+ _joints = value;
+ dispatchStrokeChangedEvent("joints", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // miterLimit
+ //----------------------------------
+
+ private var _miterLimit:Number = 3;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General", minValue="0.0", maxValue="255.0")]
+
+ /**
+ * Indicates the limit at which a miter is cut off.
+ * Valid values range from 0 to 255.
+ *
+ * @default 3
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get miterLimit():Number
+ {
+ return _miterLimit;
+ }
+
+ public function set miterLimit(value:Number):void
+ {
+ var oldValue:Number = _miterLimit;
+ if (value != oldValue)
+ {
+ _miterLimit = value;
+ dispatchStrokeChangedEvent("miterLimit", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // pixelHinting
+ //----------------------------------
+
+ private var _pixelHinting:Boolean = false;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * Specifies whether to hint strokes to full pixels.
+ * This value affects both the position of anchors of a curve
+ * and the line stroke size itself.
+ *
+ * @default false
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get pixelHinting():Boolean
+ {
+ return _pixelHinting;
+ }
+
+ public function set pixelHinting(value:Boolean):void
+ {
+ var oldValue:Boolean = _pixelHinting;
+ if (value != oldValue)
+ {
+ _pixelHinting = value;
+ dispatchStrokeChangedEvent("pixelHinting", oldValue, value);
+ }
+ }
+
+ //----------------------------------
+ // scaleMode
+ //----------------------------------
+
+ private var _scaleMode:String = "normal";
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General", enumeration="normal,vertical,horizontal,none", defaultValue="normal")]
+
+ /**
+ * A value from the LineScaleMode class
+ * that specifies which scale mode to use.
+ * Value valids are:
+ *
+ * LineScaleMode.NORMAL
+ * Always scale the line thickness when the object is scaled (the default).
+ * LineScaleMode.NONE
+ * Never scale the line thickness.
+ * LineScaleMode.VERTICAL
+ * Do not scale the line thickness if the object is scaled vertically
+ * only.
+ * LineScaleMode.HORIZONTAL
+ * Do not scale the line thickness if the object is scaled horizontally
+ * only.
+ * 4 * width * height bytes.
+ * Each pixel is represented by 4 bytes, in the order ARGB.
+ * The first four bytes represent the top-left pixel of the image.
+ * The next four bytes represent the pixel to its right, etc.
+ * Each row follows the previous one without any padding.
+ *
+ * @param width The width of the input image, in pixels.
+ *
+ * @param height The height of the input image, in pixels.
+ *
+ * @param transparent If false,
+ * alpha channel information is ignored.
+ *
+ * @return Returns a ByteArray object containing encoded image data.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function encodeByteArray(byteArray:ByteArray, width:int, height:int,
+ transparent:Boolean = true):ByteArray;
+}
+
+}
diff --git a/src/mx/graphics/codec/JPEGEncoder.as b/src/mx/graphics/codec/JPEGEncoder.as
new file mode 100644
index 00000000..9eb64f3c
--- /dev/null
+++ b/src/mx/graphics/codec/JPEGEncoder.as
@@ -0,0 +1,1070 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.graphics.codec
+{
+
+import flash.display.BitmapData;
+import flash.utils.ByteArray;
+
+/**
+ * The JPEGEncoder class converts raw bitmap images into encoded
+ * images using Joint Photographic Experts Group (JPEG) compression.
+ *
+ * For information about the JPEG algorithm, see the document
+ * http://www.opennet.ru/docs/formats/jpeg.txt by Cristi Cuturicu.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class JPEGEncoder implements IImageEncoder
+{
+ include "../../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private static const CONTENT_TYPE:String = "image/jpeg";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param quality A value between 0.0 and 100.0.
+ * The smaller the quality value,
+ * the smaller the file size of the resultant image.
+ * The value does not affect the encoding speed.
+ *. Note that even though this value is a number between 0.0 and 100.0,
+ * it does not represent a percentage.
+ * The default value is 50.0.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function JPEGEncoder(quality:Number = 50.0)
+ {
+ super();
+
+ if (quality <= 0.0)
+ quality = 1.0;
+
+ if (quality > 100.0)
+ quality = 100.0;
+
+ var sf:int = 0;
+ if (quality < 50.0)
+ sf = int(5000 / quality);
+ else
+ sf = int(200 - quality * 2);
+
+ // Create tables
+ initHuffmanTbl();
+ initCategoryNumber();
+ initQuantTables(sf);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private const std_dc_luminance_nrcodes:Array =
+ [ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 ];
+
+ /**
+ * @private
+ */
+ private const std_dc_luminance_values:Array =
+ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
+
+ /**
+ * @private
+ */
+ private const std_dc_chrominance_nrcodes:Array =
+ [ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 ];
+
+ /**
+ * @private
+ */
+ private const std_dc_chrominance_values:Array =
+ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
+
+ /**
+ * @private
+ */
+ private const std_ac_luminance_nrcodes:Array =
+ [ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7D ];
+
+ /**
+ * @private
+ */
+ private const std_ac_luminance_values:Array =
+ [
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08,
+ 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16,
+ 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
+ 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5,
+ 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4,
+ 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2,
+ 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
+ 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
+ 0xF9, 0xFA
+ ];
+
+ /**
+ * @private
+ */
+ private const std_ac_chrominance_nrcodes:Array =
+ [ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 ];
+
+ /**
+ * @private
+ */
+ private const std_ac_chrominance_values:Array =
+ [
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0,
+ 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34,
+ 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26,
+ 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5,
+ 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4,
+ 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3,
+ 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2,
+ 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
+ 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9,
+ 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
+ 0xF9, 0xFA
+ ];
+
+ /**
+ * @private
+ */
+ private const ZigZag:Array =
+ [
+ 0, 1, 5, 6, 14, 15, 27, 28,
+ 2, 4, 7, 13, 16, 26, 29, 42,
+ 3, 8, 12, 17, 25, 30, 41, 43,
+ 9, 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63
+ ];
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Initialized by initHuffmanTbl() in constructor.
+ */
+ private var YDC_HT:Array;
+
+ /**
+ * @private
+ * Initialized by initHuffmanTbl() in constructor.
+ */
+ private var UVDC_HT:Array;
+
+ /**
+ * @private
+ * Initialized by initHuffmanTbl() in constructor.
+ */
+ private var YAC_HT:Array;
+
+ /**
+ * @private
+ * Initialized by initHuffmanTbl() in constructor.
+ */
+ private var UVAC_HT:Array;
+
+ /**
+ * @private
+ * Initialized by initCategoryNumber() in constructor.
+ */
+ private var category:Array = new Array(65535);
+
+ /**
+ * @private
+ * Initialized by initCategoryNumber() in constructor.
+ */
+ private var bitcode:Array = new Array(65535);
+
+ /**
+ * @private
+ * Initialized by initQuantTables() in constructor.
+ */
+ private var YTable:Array = new Array(64);
+
+ /**
+ * @private
+ * Initialized by initQuantTables() in constructor.
+ */
+ private var UVTable:Array = new Array(64);
+
+ /**
+ * @private
+ * Initialized by initQuantTables() in constructor.
+ */
+ private var fdtbl_Y:Array = new Array(64);
+
+ /**
+ * @private
+ * Initialized by initQuantTables() in constructor.
+ */
+ private var fdtbl_UV:Array = new Array(64);
+
+ /**
+ * @private
+ * The output ByteArray containing the encoded image data.
+ */
+ private var byteout:ByteArray;
+
+ /**
+ * @private
+ */
+ private var bytenew:int = 0;
+
+ /**
+ * @private
+ */
+ private var bytepos:int = 7;
+
+ /**
+ * @private
+ */
+ private var DU:Array = new Array(64);
+
+ /**
+ * @private
+ */
+ private var YDU:Array = new Array(64);
+
+ /**
+ * @private
+ */
+ private var UDU:Array = new Array(64);
+
+ /**
+ * @private
+ */
+ private var VDU:Array = new Array(64);
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // contentType
+ //----------------------------------
+
+ /**
+ * The MIME type for the JPEG encoded image.
+ * The value is "image/jpeg".
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get contentType():String
+ {
+ return CONTENT_TYPE;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Converts the pixels of BitmapData object
+ * to a JPEG-encoded ByteArray object.
+ *
+ * @param bitmapData The input BitmapData object.
+ *
+ * @return Returns a ByteArray object containing JPEG-encoded image data.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function encode(bitmapData:BitmapData):ByteArray
+ {
+ return internalEncode(bitmapData, bitmapData.width, bitmapData.height,
+ bitmapData.transparent);
+ }
+
+ /**
+ * Converts a ByteArray object containing raw pixels
+ * in 32-bit ARGB (Alpha, Red, Green, Blue) format
+ * to a new JPEG-encoded ByteArray object.
+ * The original ByteArray is left unchanged.
+ * Transparency is not supported; however you still must represent
+ * each pixel as four bytes in ARGB format.
+ *
+ * @param byteArray The input ByteArray object containing raw pixels.
+ * This ByteArray should contain
+ * 4 * width * height bytes.
+ * Each pixel is represented by 4 bytes, in the order ARGB.
+ * The first four bytes represent the top-left pixel of the image.
+ * The next four bytes represent the pixel to its right, etc.
+ * Each row follows the previous one without any padding.
+ *
+ * @param width The width of the input image, in pixels.
+ *
+ * @param height The height of the input image, in pixels.
+ *
+ * @param transparent If false,
+ * alpha channel information is ignored.
+ *
+ * @return Returns a ByteArray object containing JPEG-encoded image data.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function encodeByteArray(byteArray:ByteArray, width:int, height:int,
+ transparent:Boolean = true):ByteArray
+ {
+ return internalEncode(byteArray, width, height, transparent);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods: Initialization
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Initializes the Huffman tables YDC_HT, UVDC_HT, YAC_HT, and UVAC_HT.
+ */
+ private function initHuffmanTbl():void
+ {
+ YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes,
+ std_dc_luminance_values);
+
+ UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes,
+ std_dc_chrominance_values);
+
+ YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes,
+ std_ac_luminance_values);
+
+ UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes,
+ std_ac_chrominance_values);
+ }
+
+ /**
+ * @private
+ */
+ private function computeHuffmanTbl(nrcodes:Array, std_table:Array):Array
+ {
+ var codevalue:int = 0;
+ var pos_in_table:int = 0;
+
+ var HT:Array = [];
+
+ for (var k:int = 1; k <= 16; k++)
+ {
+ for (var j:int = 1; j <= nrcodes[k]; j++)
+ {
+ HT[std_table[pos_in_table]] = new BitString();
+ HT[std_table[pos_in_table]].val = codevalue;
+ HT[std_table[pos_in_table]].len = k;
+
+ pos_in_table++;
+ codevalue++;
+ }
+
+ codevalue *= 2;
+ }
+
+ return HT;
+ }
+
+ /**
+ * @private
+ * Initializes the category and bitcode arrays.
+ */
+ private function initCategoryNumber():void
+ {
+ var nr:int;
+
+ var nrlower:int = 1;
+ var nrupper:int = 2;
+
+ for (var cat:int = 1; cat <= 15; cat++)
+ {
+ // Positive numbers
+ for (nr = nrlower; nr < nrupper; nr++)
+ {
+ category[32767 + nr] = cat;
+
+ bitcode[32767 + nr] = new BitString();
+ bitcode[32767 + nr].len = cat;
+ bitcode[32767 + nr].val = nr;
+ }
+
+ // Negative numbers
+ for (nr = -(nrupper - 1); nr <= -nrlower; nr++)
+ {
+ category[32767 + nr] = cat;
+
+ bitcode[32767 + nr] = new BitString();
+ bitcode[32767 + nr].len = cat;
+ bitcode[32767 + nr].val = nrupper - 1 + nr;
+ }
+
+ nrlower <<= 1;
+ nrupper <<= 1;
+ }
+ }
+
+ /**
+ * @private
+ * Initializes YTable, UVTable, fdtbl_Y, and fdtbl_UV.
+ */
+ private function initQuantTables(sf:int):void
+ {
+ var i:int = 0;
+ var t:Number;
+
+ var YQT:Array =
+ [
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+ ];
+
+ for (i = 0; i < 64; i++)
+ {
+ t = Math.floor((YQT[i] * sf + 50)/100);
+ if (t < 1)
+ t = 1;
+ else if (t > 255)
+ t = 255;
+ YTable[ZigZag[i]] = t;
+ }
+
+ var UVQT:Array =
+ [
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+ ];
+
+ for (i = 0; i < 64; i++)
+ {
+ t = Math.floor((UVQT[i] * sf + 50) / 100);
+ if (t < 1)
+ t = 1;
+ else if (t > 255)
+ t = 255;
+ UVTable[ZigZag[i]] = t;
+ }
+
+ var aasf:Array =
+ [
+ 1.0, 1.387039845, 1.306562965, 1.175875602,
+ 1.0, 0.785694958, 0.541196100, 0.275899379
+ ];
+
+ i = 0;
+ for (var row:int = 0; row < 8; row++)
+ {
+ for (var col:int = 0; col < 8; col++)
+ {
+ fdtbl_Y[i] =
+ (1.0 / (YTable [ZigZag[i]] * aasf[row] * aasf[col] * 8.0));
+
+ fdtbl_UV[i] =
+ (1.0 / (UVTable[ZigZag[i]] * aasf[row] * aasf[col] * 8.0));
+
+ i++;
+ }
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods: Core processing
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private function internalEncode(source:Object, width:int, height:int,
+ transparent:Boolean = true):ByteArray
+ {
+ // The source is either a BitmapData or a ByteArray.
+ var sourceBitmapData:BitmapData = source as BitmapData;
+ var sourceByteArray:ByteArray = source as ByteArray;
+
+ // Initialize bit writer
+ byteout = new ByteArray();
+ bytenew = 0;
+ bytepos = 7;
+
+ // Add JPEG headers
+ writeWord(0xFFD8); // SOI
+ writeAPP0();
+ writeDQT();
+ writeSOF0(width, height);
+ writeDHT();
+ writeSOS();
+
+ // Encode 8x8 macroblocks
+ var DCY:Number = 0;
+ var DCU:Number = 0;
+ var DCV:Number = 0;
+ bytenew = 0;
+ bytepos = 7;
+
+ for (var ypos:int = 0; ypos < height; ypos += 8)
+ {
+ for (var xpos:int = 0; xpos < width; xpos += 8)
+ {
+ RGB2YUV(sourceBitmapData, sourceByteArray, xpos, ypos, width, height);
+
+ DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
+ DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
+ DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
+ }
+ }
+
+ // Do the bit alignment of the EOI marker
+ if (bytepos >= 0)
+ {
+ var fillbits:BitString = new BitString();
+ fillbits.len = bytepos + 1;
+ fillbits.val = (1 << (bytepos + 1)) - 1;
+ writeBits(fillbits);
+ }
+
+ // Add EOI
+ writeWord(0xFFD9);
+
+ return byteout;
+ }
+
+ /**
+ * @private
+ */
+ private function RGB2YUV(sourceBitmapData:BitmapData,
+ sourceByteArray:ByteArray,
+ xpos:int, ypos:int,
+ width:int, height:int):void
+ {
+ var k:int = 0; // index into 64-element block arrays
+
+ for (var j:int = 0; j < 8; j++)
+ {
+ var y:int = ypos + j;
+ if (y >= height)
+ y = height - 1;
+
+ for (var i:int = 0; i < 8; i++)
+ {
+ var x:int = xpos + i;
+ if (x >= width)
+ x = width - 1;
+
+ var pixel:uint;
+ if (sourceBitmapData)
+ {
+ pixel = sourceBitmapData.getPixel32(x, y);
+ }
+ else
+ {
+ sourceByteArray.position = 4 * (y * width + x);
+ pixel = sourceByteArray.readUnsignedInt();
+ }
+
+ var r:Number = Number((pixel >> 16) & 0xFF);
+ var g:Number = Number((pixel >> 8) & 0xFF);
+ var b:Number = Number(pixel & 0xFF);
+
+ YDU[k] = 0.29900 * r + 0.58700 * g + 0.11400 * b - 128.0;
+ UDU[k] = -0.16874 * r - 0.33126 * g + 0.50000 * b;
+ VDU[k] = 0.50000 * r - 0.41869 * g - 0.08131 * b;
+
+ k++;
+ }
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function processDU(CDU:Array, fdtbl:Array, DC:Number,
+ HTDC:Array, HTAC:Array):Number
+ {
+ var EOB:BitString = HTAC[0x00];
+ var M16zeroes:BitString = HTAC[0xF0];
+ var i:int;
+
+ var DU_DCT:Array = fDCTQuant(CDU, fdtbl);
+
+ // ZigZag reorder
+ for (i = 0; i < 64; i++)
+ {
+ DU[ZigZag[i]] = DU_DCT[i];
+ }
+
+ var Diff:int = DU[0] - DC;
+ DC = DU[0];
+
+ // Encode DC
+ if (Diff == 0)
+ {
+ writeBits(HTDC[0]); // Diff might be 0
+ }
+ else
+ {
+ writeBits(HTDC[category[32767 + Diff]]);
+ writeBits(bitcode[32767 + Diff]);
+ }
+
+ // Encode ACs
+ var end0pos:int = 63;
+ for (; (end0pos > 0) && (DU[end0pos] == 0); end0pos--)
+ {
+ };
+
+ // end0pos = first element in reverse order != 0
+ if (end0pos == 0)
+ {
+ writeBits(EOB);
+ return DC;
+ }
+
+ i = 1;
+ while (i <= end0pos)
+ {
+ var startpos:int = i;
+ for (; (DU[i] == 0) && (i <= end0pos); i++)
+ {
+ }
+ var nrzeroes:int = i - startpos;
+
+ if (nrzeroes >= 16)
+ {
+ for (var nrmarker:int = 1; nrmarker <= nrzeroes / 16; nrmarker++)
+ {
+ writeBits(M16zeroes);
+ }
+ nrzeroes = int(nrzeroes & 0xF);
+ }
+
+ writeBits(HTAC[nrzeroes * 16 + category[32767 + DU[i]]]);
+ writeBits(bitcode[32767 + DU[i]]);
+
+ i++;
+ }
+
+ if (end0pos != 63)
+ writeBits(EOB);
+
+ return DC;
+ }
+
+ /**
+ * @private
+ */
+ private function fDCTQuant(data:Array, fdtbl:Array):Array
+ {
+ // Pass 1: process rows.
+ var dataOff:int = 0;
+ var i:int;
+ for (i = 0; i < 8; i++)
+ {
+ var tmp0:Number = data[dataOff + 0] + data[dataOff + 7];
+ var tmp7:Number = data[dataOff + 0] - data[dataOff + 7];
+ var tmp1:Number = data[dataOff + 1] + data[dataOff + 6];
+ var tmp6:Number = data[dataOff + 1] - data[dataOff + 6];
+ var tmp2:Number = data[dataOff + 2] + data[dataOff + 5];
+ var tmp5:Number = data[dataOff + 2] - data[dataOff + 5];
+ var tmp3:Number = data[dataOff + 3] + data[dataOff + 4];
+ var tmp4:Number = data[dataOff + 3] - data[dataOff + 4];
+
+ // Even part
+ var tmp10:Number = tmp0 + tmp3; // phase 2
+ var tmp13:Number = tmp0 - tmp3;
+ var tmp11:Number = tmp1 + tmp2;
+ var tmp12:Number = tmp1 - tmp2;
+
+ data[dataOff + 0] = tmp10 + tmp11; // phase 3
+ data[dataOff + 4] = tmp10 - tmp11;
+
+ var z1:Number = (tmp12 + tmp13) * 0.707106781; // c4
+ data[dataOff + 2] = tmp13 + z1; // phase 5
+ data[dataOff + 6] = tmp13 - z1;
+
+ // Odd part
+ tmp10 = tmp4 + tmp5; // phase 2
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ // The rotator is modified from fig 4-8 to avoid extra negations.
+ var z5:Number = (tmp10 - tmp12) * 0.382683433; // c6
+ var z2:Number = 0.541196100 * tmp10 + z5; // c2 - c6
+ var z4:Number = 1.306562965 * tmp12 + z5; // c2 + c6
+ var z3:Number = tmp11 * 0.707106781; // c4
+
+ var z11:Number = tmp7 + z3; // phase 5
+ var z13:Number = tmp7 - z3;
+
+ data[dataOff + 5] = z13 + z2; // phase 6
+ data[dataOff + 3] = z13 - z2;
+ data[dataOff + 1] = z11 + z4;
+ data[dataOff + 7] = z11 - z4;
+
+ dataOff += 8; // advance pointer to next row
+ }
+
+ // Pass 2: process columns.
+ dataOff = 0;
+ for (i = 0; i < 8; i++)
+ {
+ tmp0 = data[dataOff + 0] + data[dataOff + 56];
+ tmp7 = data[dataOff + 0] - data[dataOff + 56];
+ tmp1 = data[dataOff + 8] + data[dataOff + 48];
+ tmp6 = data[dataOff + 8] - data[dataOff + 48];
+ tmp2 = data[dataOff + 16] + data[dataOff + 40];
+ tmp5 = data[dataOff + 16] - data[dataOff + 40];
+ tmp3 = data[dataOff + 24] + data[dataOff + 32];
+ tmp4 = data[dataOff + 24] - data[dataOff + 32];
+
+ // Even par
+ tmp10 = tmp0 + tmp3; // phase 2
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ data[dataOff + 0] = tmp10 + tmp11; // phase 3
+ data[dataOff + 32] = tmp10 - tmp11;
+
+ z1 = (tmp12 + tmp13) * 0.707106781; // c4
+ data[dataOff + 16] = tmp13 + z1; // phase 5
+ data[dataOff + 48] = tmp13 - z1;
+
+ // Odd part
+ tmp10 = tmp4 + tmp5; // phase 2
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ // The rotator is modified from fig 4-8 to avoid extra negations.
+ z5 = (tmp10 - tmp12) * 0.382683433; // c6
+ z2 = 0.541196100 * tmp10 + z5; // c2 - c6
+ z4 = 1.306562965 * tmp12 + z5; // c2 + c6
+ z3 = tmp11 * 0.707106781; // c4
+
+ z11 = tmp7 + z3; // phase 5 */
+ z13 = tmp7 - z3;
+
+ data[dataOff + 40] = z13 + z2; // phase 6
+ data[dataOff + 24] = z13 - z2;
+ data[dataOff + 8] = z11 + z4;
+ data[dataOff + 56] = z11 - z4;
+
+ dataOff++; // advance pointer to next column
+ }
+
+ // Quantize/descale the coefficients
+ for (i = 0; i < 64; i++)
+ {
+ // Apply the quantization and scaling factor
+ // and round to nearest integer
+ data[i] = Math.round((data[i] * fdtbl[i]));
+ }
+
+ return data;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods: Output
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private function writeBits(bs:BitString):void
+ {
+ var value:int = bs.val;
+ var posval:int = bs.len - 1;
+ while (posval >= 0)
+ {
+ if (value & uint(1 << posval) )
+ {
+ bytenew |= uint(1 << bytepos);
+ }
+ posval--;
+ bytepos--;
+ if (bytepos < 0)
+ {
+ if (bytenew == 0xFF)
+ {
+ writeByte(0xFF);
+ writeByte(0);
+ }
+ else
+ {
+ writeByte(bytenew);
+ }
+ bytepos = 7;
+ bytenew = 0;
+ }
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function writeByte(value:int):void
+ {
+ byteout.writeByte(value);
+ }
+
+ /**
+ * @private
+ */
+ private function writeWord(value:int):void
+ {
+ writeByte((value >> 8) & 0xFF);
+ writeByte(value & 0xFF);
+ }
+
+ /**
+ * @private
+ */
+ private function writeAPP0():void
+ {
+ writeWord(0xFFE0); // marker
+ writeWord(16); // length
+ writeByte(0x4A); // J
+ writeByte(0x46); // F
+ writeByte(0x49); // I
+ writeByte(0x46); // F
+ writeByte(0); // = "JFIF",'\0'
+ writeByte(1); // versionhi
+ writeByte(1); // versionlo
+ writeByte(0); // xyunits
+ writeWord(1); // xdensity
+ writeWord(1); // ydensity
+ writeByte(0); // thumbnwidth
+ writeByte(0); // thumbnheight
+ }
+
+ /**
+ * @private
+ */
+ private function writeDQT():void
+ {
+ writeWord(0xFFDB); // marker
+ writeWord(132); // length
+ writeByte(0);
+ var i:int;
+
+ for (i = 0; i < 64; i++)
+ {
+ writeByte(YTable[i]);
+ }
+
+ writeByte(1);
+
+ for (i = 0; i < 64; i++)
+ {
+ writeByte(UVTable[i]);
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function writeSOF0(width:int, height:int):void
+ {
+ writeWord(0xFFC0); // marker
+ writeWord(17); // length, truecolor YUV JPG
+ writeByte(8); // precision
+ writeWord(height);
+ writeWord(width);
+ writeByte(3); // nrofcomponents
+ writeByte(1); // IdY
+ writeByte(0x11); // HVY
+ writeByte(0); // QTY
+ writeByte(2); // IdU
+ writeByte(0x11); // HVU
+ writeByte(1); // QTU
+ writeByte(3); // IdV
+ writeByte(0x11); // HVV
+ writeByte(1); // QTV
+ }
+
+ /**
+ * @private
+ */
+ private function writeDHT():void
+ {
+ var i:int;
+
+ writeWord(0xFFC4); // marker
+ writeWord(0x01A2); // length
+
+ writeByte(0); // HTYDCinfo
+ for (i = 0; i < 16; i++)
+ {
+ writeByte(std_dc_luminance_nrcodes[i + 1]);
+ }
+ for (i = 0; i <= 11; i++)
+ {
+ writeByte(std_dc_luminance_values[i]);
+ }
+
+ writeByte(0x10); // HTYACinfo
+ for (i = 0; i < 16; i++)
+ {
+ writeByte(std_ac_luminance_nrcodes[i + 1]);
+ }
+ for (i = 0; i <= 161; i++)
+ {
+ writeByte(std_ac_luminance_values[i]);
+ }
+
+ writeByte(1); // HTUDCinfo
+ for (i = 0; i < 16; i++)
+ {
+ writeByte(std_dc_chrominance_nrcodes[i + 1]);
+ }
+ for (i = 0; i <= 11; i++)
+ {
+ writeByte(std_dc_chrominance_values[i]);
+ }
+
+ writeByte(0x11); // HTUACinfo
+ for (i = 0; i < 16; i++)
+ {
+ writeByte(std_ac_chrominance_nrcodes[i + 1]);
+ }
+ for (i = 0; i <= 161; i++)
+ {
+ writeByte(std_ac_chrominance_values[i]);
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function writeSOS():void
+ {
+ writeWord(0xFFDA); // marker
+ writeWord(12); // length
+ writeByte(3); // nrofcomponents
+ writeByte(1); // IdY
+ writeByte(0); // HTY
+ writeByte(2); // IdU
+ writeByte(0x11); // HTU
+ writeByte(3); // IdV
+ writeByte(0x11); // HTV
+ writeByte(0); // Ss
+ writeByte(0x3f); // Se
+ writeByte(0); // Bf
+ }
+}
+
+}
+
+class BitString
+{
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function BitString()
+ {
+ super();
+ }
+
+ /**
+ * @private
+ */
+ public var len:int = 0;
+
+ /**
+ * @private
+ */
+ public var val:int = 0;
+}
diff --git a/src/mx/graphics/codec/PNGEncoder.as b/src/mx/graphics/codec/PNGEncoder.as
new file mode 100644
index 00000000..b4ea6988
--- /dev/null
+++ b/src/mx/graphics/codec/PNGEncoder.as
@@ -0,0 +1,295 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.graphics.codec
+{
+
+import flash.display.BitmapData;
+import flash.utils.ByteArray;
+
+/**
+ * The PNGEncoder class converts raw bitmap images into encoded
+ * images using Portable Network Graphics (PNG) lossless compression.
+ *
+ * For the PNG specification, see http://www.w3.org/TR/PNG/
. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class PNGEncoder implements IImageEncoder +{ + include "../../core/Version.as"; + + //-------------------------------------------------------------------------- + // + // Class constants + // + //-------------------------------------------------------------------------- + + /** + * @private + * The MIME type for a PNG image. + */ + private static const CONTENT_TYPE:String = "image/png"; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function PNGEncoder() + { + super(); + + initializeCRCTable(); + } + + //-------------------------------------------------------------------------- + // + // Variables + // + //-------------------------------------------------------------------------- + + /** + * @private + * Used for computing the cyclic redundancy checksum + * at the end of each chunk. + */ + private var crcTable:Array; + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // contentType + //---------------------------------- + + /** + * The MIME type for the PNG encoded image. + * The value is"image/png".
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get contentType():String
+ {
+ return CONTENT_TYPE;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Converts the pixels of a BitmapData object
+ * to a PNG-encoded ByteArray object.
+ *
+ * @param bitmapData The input BitmapData object.
+ *
+ * @return Returns a ByteArray object containing PNG-encoded image data.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function encode(bitmapData:BitmapData):ByteArray
+ {
+ return internalEncode(bitmapData, bitmapData.width, bitmapData.height,
+ bitmapData.transparent);
+ }
+
+ /**
+ * Converts a ByteArray object containing raw pixels
+ * in 32-bit ARGB (Alpha, Red, Green, Blue) format
+ * to a new PNG-encoded ByteArray object.
+ * The original ByteArray is left unchanged.
+ *
+ * @param byteArray The input ByteArray object containing raw pixels.
+ * This ByteArray should contain
+ * 4 * width * height bytes.
+ * Each pixel is represented by 4 bytes, in the order ARGB.
+ * The first four bytes represent the top-left pixel of the image.
+ * The next four bytes represent the pixel to its right, etc.
+ * Each row follows the previous one without any padding.
+ *
+ * @param width The width of the input image, in pixels.
+ *
+ * @param height The height of the input image, in pixels.
+ *
+ * @param transparent If false, alpha channel information
+ * is ignored but you still must represent each pixel
+ * as four bytes in ARGB format.
+ *
+ * @return Returns a ByteArray object containing PNG-encoded image data.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function encodeByteArray(byteArray:ByteArray, width:int, height:int,
+ transparent:Boolean = true):ByteArray
+ {
+ return internalEncode(byteArray, width, height, transparent);
+ }
+
+ /**
+ * @private
+ */
+ private function initializeCRCTable():void
+ {
+ crcTable = [];
+
+ for (var n:uint = 0; n < 256; n++)
+ {
+ var c:uint = n;
+ for (var k:uint = 0; k < 8; k++)
+ {
+ if (c & 1)
+ c = uint(uint(0xedb88320) ^ uint(c >>> 1));
+ else
+ c = uint(c >>> 1);
+ }
+ crcTable[n] = c;
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function internalEncode(source:Object, width:int, height:int,
+ transparent:Boolean = true):ByteArray
+ {
+ // The source is either a BitmapData or a ByteArray.
+ var sourceBitmapData:BitmapData = source as BitmapData;
+ var sourceByteArray:ByteArray = source as ByteArray;
+
+ if (sourceByteArray)
+ sourceByteArray.position = 0;
+
+ // Create output byte array
+ var png:ByteArray = new ByteArray();
+
+ // Write PNG signature
+ png.writeUnsignedInt(0x89504E47);
+ png.writeUnsignedInt(0x0D0A1A0A);
+
+ // Build IHDR chunk
+ var IHDR:ByteArray = new ByteArray();
+ IHDR.writeInt(width);
+ IHDR.writeInt(height);
+ IHDR.writeByte(8); // bit depth per channel
+ IHDR.writeByte(6); // color type: RGBA
+ IHDR.writeByte(0); // compression method
+ IHDR.writeByte(0); // filter method
+ IHDR.writeByte(0); // interlace method
+ writeChunk(png, 0x49484452, IHDR);
+
+ // Build IDAT chunk
+ var IDAT:ByteArray = new ByteArray();
+ for (var y:int = 0; y < height; y++)
+ {
+ IDAT.writeByte(0); // no filter
+
+ var x:int;
+ var pixel:uint;
+
+ if (!transparent)
+ {
+ for (x = 0; x < width; x++)
+ {
+ if (sourceBitmapData)
+ pixel = sourceBitmapData.getPixel(x, y);
+ else
+ pixel = sourceByteArray.readUnsignedInt();
+
+ IDAT.writeUnsignedInt(uint(((pixel & 0xFFFFFF) << 8) | 0xFF));
+ }
+ }
+ else
+ {
+ for (x = 0; x < width; x++)
+ {
+ if (sourceBitmapData)
+ pixel = sourceBitmapData.getPixel32(x, y);
+ else
+ pixel = sourceByteArray.readUnsignedInt();
+
+ IDAT.writeUnsignedInt(uint(((pixel & 0xFFFFFF) << 8) |
+ (pixel >>> 24)));
+ }
+ }
+ }
+ IDAT.compress();
+ writeChunk(png, 0x49444154, IDAT);
+
+ // Build IEND chunk
+ writeChunk(png, 0x49454E44, null);
+
+ // return PNG
+ png.position = 0;
+ return png;
+ }
+
+ /**
+ * @private
+ */
+ private function writeChunk(png:ByteArray, type:uint, data:ByteArray):void
+ {
+ // Write length of data.
+ var len:uint = 0;
+ if (data)
+ len = data.length;
+ png.writeUnsignedInt(len);
+
+ // Write chunk type.
+ var typePos:uint = png.position;
+ png.writeUnsignedInt(type);
+
+ // Write data.
+ if (data)
+ png.writeBytes(data);
+
+ // Write CRC of chunk type and data.
+ var crcPos:uint = png.position;
+ png.position = typePos;
+ var crc:uint = 0xFFFFFFFF;
+ for (var i:uint = typePos; i < crcPos; i++)
+ {
+ crc = uint(crcTable[(crc ^ png.readUnsignedByte()) & uint(0xFF)] ^
+ uint(crc >>> 8));
+ }
+ crc = uint(crc ^ uint(0xFFFFFFFF));
+ png.position = crcPos;
+ png.writeUnsignedInt(crc);
+ }
+}
+
+}
diff --git a/src/mx/logging/AbstractTarget.as b/src/mx/logging/AbstractTarget.as
new file mode 100644
index 00000000..c4630536
--- /dev/null
+++ b/src/mx/logging/AbstractTarget.as
@@ -0,0 +1,386 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.logging
+{
+
+import mx.core.IMXMLObject;
+import mx.logging.errors.InvalidFilterError;
+import mx.managers.ISystemManager;
+import mx.managers.SystemManager;
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+import mx.utils.UIDUtil;
+
+[ResourceBundle("logging")]
+
+/**
+ * This class provides the basic functionality required by the logging framework
+ * for a target implementation.
+ * It handles the validation of filter expressions and provides a default level
+ * property.
+ * No implementation of the logEvent() method is provided.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class AbstractTarget implements ILoggingTarget, IMXMLObject
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function AbstractTarget()
+ {
+ super();
+
+ _id = UIDUtil.createUID();
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Count of the number of loggers this target is listening to. When this
+ * value is zero changes to the filters property shouldn't do anything
+ */
+ private var _loggerCount:uint = 0;
+
+ /**
+ * @private
+ * Used for accessing localized Error messages.
+ */
+ private var resourceManager:IResourceManager =
+ ResourceManager.getInstance();
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // filters
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the filters property.
+ */
+ private var _filters:Array = [ "*" ];
+
+ [Inspectable(category="General", arrayType="String")]
+
+ /**
+ * In addition to the level setting, filters are used to
+ * provide a psuedo-hierarchical mapping for processing only those events
+ * for a given category.
+ *
+ * Each logger belongs to a category.
+ * By convention these categories map to the fully-qualified class name in
+ * which the logger is used.
+ * For example, a logger that is logging messages for the
+ * mx.rpc.soap.WebService class, uses
+ * "mx.rpc.soap.WebService" as the parameter to the
+ * Log.getLogger() method call.
+ * When messages are sent under this category only those targets that have
+ * a filter which matches that category receive notification of those
+ * events.
+ * Filter expressions can include a wildcard match, indicated with an
+ * asterisk.
+ * The wildcard must be the right-most character in the expression.
+ * For example: rpc~~, mx.~~, or ~~.
+ * If an invalid expression is specified, a InvalidFilterError
+ * is thrown.
+ * If null or [] is specified, the filters are set to the
+ * default of ["~~"].
+ *
For example: + *
+ * var traceLogger:ILoggingTarget = new TraceTarget(); + * traceLogger.filters = ["mx.rpc.~~", "mx.messaging.~~"]; + * Log.addTarget(traceLogger); + *+ * + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get filters():Array + { + return _filters; + } + + /** + * @private + * This method will make sure that all of the filter expressions specified + * are valid, and will throw
InvalidFilterError if any are not.
+ */
+ public function set filters(value:Array):void
+ {
+ if (value && value.length > 0)
+ {
+ // a valid filter value will be fully qualified or have a wildcard
+ // in it. the wild card can only be located at the end of the
+ // expression. valid examples xx*, xx.*, *
+ var filter:String;
+ var index:int;
+ var message:String;
+ for (var i:uint = 0; iLogEventLevel.FATAL (1000) designates events that are very
+ * harmful and will eventually lead to application failureLogEventLevel.ERROR (8) designates error events that might
+ * still allow the application to continue running.LogEventLevel.WARN (6) designates events that could be
+ * harmful to the application operationLogEventLevel.INFO (4) designates informational messages
+ * that highlight the progress of the application at
+ * coarse-grained level.LogEventLevel.DEBUG (2) designates informational
+ * level messages that are fine grained and most helpful when
+ * debugging an application.LogEventLevel.ALL (0) intended to force a target to
+ * process all messages.LogEvent from an associated logger.
+ * A target uses this method to translate the event into the appropriate
+ * format for transmission, storage, or display.
+ * This method will be called only if the event's level is in range of the
+ * target's level.
+ *
+ * NOTE: Descendants must override this method to make it useful.
+ * + * @param event An event from an associated logger. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function logEvent(event:LogEvent):void + { + } + + //-------------------------------------------------------------------------- + // + // Event handlers + // + //-------------------------------------------------------------------------- + + /** + * @private + * This method will call thelogEvent method if the level of the
+ * event is appropriate for the current level.
+ */
+ private function logHandler(event:LogEvent):void
+ {
+ if (event.level >= level)
+ logEvent(event);
+ }
+}
+
+}
diff --git a/src/mx/logging/ILogger.as b/src/mx/logging/ILogger.as
new file mode 100644
index 00000000..c6ad3a6b
--- /dev/null
+++ b/src/mx/logging/ILogger.as
@@ -0,0 +1,320 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.logging
+{
+
+import flash.events.IEventDispatcher;
+
+/**
+ * All loggers within the logging framework must implement this interface.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public interface ILogger extends IEventDispatcher
+{
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // category
+ //----------------------------------
+
+ /**
+ * The category value for the logger.
+ *
+ * @return String containing the category for this logger.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get category():String;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Logs the specified data at the given level.
+ *
+ * The String specified for logging can contain braces with an index + * indicating which additional parameter should be inserted + * into the String before it is logged. + * For example "the first additional parameter was {0} the second was {1}" + * is translated into "the first additional parameter was 10 the + * second was 15" when called with 10 and 15 as parameters.
+ * + * @param level The level this information should be logged at. + * Valid values are: + *LogEventLevel.FATAL designates events that are very
+ * harmful and will eventually lead to application failureLogEventLevel.ERROR designates error events
+ * that might still allow the application to continue running.LogEventLevel.WARN designates events that could be
+ * harmful to the application operationLogEventLevel.INFO designates informational messages
+ * that highlight the progress of the application at
+ * coarse-grained level.LogEventLevel.DEBUG designates informational
+ * level messages that are fine grained and most helpful when
+ * debugging an application.x}" location, where x
+ * is an integer (zero based) index value into the Array of values
+ * specified.
+ *
+ * @example
+ *
+ * // Get the logger for the mx.messaging.Channel "category"
+ * // and send some data to it.
+ * var logger:ILogger = Log.getLogger("mx.messaging.Channel");
+ * logger.log(LogEventLevel.DEBUG, "here is some channel info {0} and {1}", LogEventLevel.DEBUG, 15.4, true);
+ *
+ * // This will log the following String as a DEBUG log message:
+ * // "here is some channel info 15.4 and true"
+ *
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function log(level:int, message:String, ... rest):void;
+
+ /**
+ * Logs the specified data using the LogEventLevel.DEBUG
+ * level.
+ * LogEventLevel.DEBUG designates informational level
+ * messages that are fine grained and most helpful when debugging
+ * an application.
+ *
+ * The string specified for logging can contain braces with an index + * indicating which additional parameter should be inserted + * into the string before it is logged. + * For example "the first additional parameter was {0} the second was {1}" + * will be translated into "the first additional parameter was 10 the + * second was 15" when called with 10 and 15 as parameters.
+ * + * @param message The information to log. + * This string can contain special marker characters of the form {x}, + * where x is a zero based index that will be replaced with + * the additional parameters found at that index if specified. + * + * @param rest Additional parameters that can be subsituted in the str + * parameter at each "{x}" location, where x
+ * is an integer (zero based) index value into the Array of values
+ * specified.
+ *
+ * @example
+ *
+ * // Get the logger for the mx.messaging.Channel "category"
+ * // and send some data to it.
+ * var logger:ILogger = Log.getLogger("mx.messaging.Channel");
+ * logger.debug("here is some channel info {0} and {1}", 15.4, true);
+ *
+ * // This will log the following String:
+ * // "here is some channel info 15.4 and true"
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function debug(message:String, ... rest):void;
+
+ /**
+ * Logs the specified data using the LogEventLevel.ERROR
+ * level.
+ * LogEventLevel.ERROR designates error events
+ * that might still allow the application to continue running.
+ *
+ * The string specified for logging can contain braces with an index + * indicating which additional parameter should be inserted + * into the string before it is logged. + * For example "the first additional parameter was {0} the second was {1}" + * will be translated into "the first additional parameter was 10 the + * second was 15" when called with 10 and 15 as parameters.
+ * + * @param message The information to log. + * This String can contain special marker characters of the form {x}, + * where x is a zero based index that will be replaced with + * the additional parameters found at that index if specified. + * + * @param rest Additional parameters that can be subsituted in the str + * parameter at each "{x}" location, where x
+ * is an integer (zero based) index value into the Array of values
+ * specified.
+ *
+ * @example
+ *
+ * // Get the logger for the mx.messaging.Channel "category"
+ * // and send some data to it.
+ * var logger:ILogger = Log.getLogger("mx.messaging.Channel");
+ * logger.error("here is some channel info {0} and {1}", 15.4, true);
+ *
+ * // This will log the following String:
+ * // "here is some channel info 15.4 and true"
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function error(message:String, ... rest):void;
+
+ /**
+ * Logs the specified data using the LogEventLevel.FATAL
+ * level.
+ * LogEventLevel.FATAL designates events that are very
+ * harmful and will eventually lead to application failure
+ *
+ * The string specified for logging can contain braces with an index + * indicating which additional parameter should be inserted + * into the string before it is logged. + * For example "the first additional parameter was {0} the second was {1}" + * will be translated into "the first additional parameter was 10 the + * second was 15" when called with 10 and 15 as parameters.
+ * + * @param message The information to log. + * This String can contain special marker characters of the form {x}, + * where x is a zero based index that will be replaced with + * the additional parameters found at that index if specified. + * + * @param rest Additional parameters that can be subsituted in the str + * parameter at each "{x}" location, where x
+ * is an integer (zero based) index value into the Array of values
+ * specified.
+ *
+ * @example
+ *
+ * // Get the logger for the mx.messaging.Channel "category"
+ * // and send some data to it.
+ * var logger:ILogger = Log.getLogger("mx.messaging.Channel");
+ * logger.fatal("here is some channel info {0} and {1}", 15.4, true);
+ *
+ * // This will log the following String:
+ * // "here is some channel info 15.4 and true"
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function fatal(message:String, ... rest):void;
+
+ /**
+ * Logs the specified data using the LogEvent.INFO level.
+ * LogEventLevel.INFO designates informational messages that
+ * highlight the progress of the application at coarse-grained level.
+ *
+ * The string specified for logging can contain braces with an index + * indicating which additional parameter should be inserted + * into the string before it is logged. + * For example "the first additional parameter was {0} the second was {1}" + * will be translated into "the first additional parameter was 10 the + * second was 15" when called with 10 and 15 as parameters.
+ * + * @param message The information to log. + * This String can contain special marker characters of the form {x}, + * where x is a zero based index that will be replaced with + * the additional parameters found at that index if specified. + * + * @param rest Additional parameters that can be subsituted in the str + * parameter at each "{x}" location, where x
+ * is an integer (zero based) index value into the Array of values
+ * specified.
+ *
+ * @example
+ *
+ * // Get the logger for the mx.messaging.Channel "category"
+ * // and send some data to it.
+ * var logger:ILogger = Log.getLogger("mx.messaging.Channel");
+ * logger.info("here is some channel info {0} and {1}", 15.4, true);
+ *
+ * // This will log the following String:
+ * // "here is some channel info 15.4 and true"
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function info(message:String, ... rest):void;
+
+ /**
+ * Logs the specified data using the LogEventLevel.WARN level.
+ * LogEventLevel.WARN designates events that could be harmful
+ * to the application operation.
+ *
+ * The string specified for logging can contain braces with an index + * indicating which additional parameter should be inserted + * into the string before it is logged. + * For example "the first additional parameter was {0} the second was {1}" + * will be translated into "the first additional parameter was 10 the + * second was 15" when called with 10 and 15 as parameters.
+ * + * @param message The information to log. + * This String can contain special marker characters of the form {x}, + * where x is a zero based index that will be replaced with + * the additional parameters found at that index if specified. + * + * @param rest Aadditional parameters that can be subsituted in the str + * parameter at each "{x}" location, where x
+ * is an integer (zero based) index value into the Array of values
+ * specified.
+ *
+ * @example
+ *
+ * // Get the logger for the mx.messaging.Channel "category"
+ * // and send some data to it.
+ * var logger:ILogger = Log.getLogger("mx.messaging.Channel");
+ * logger.warn("here is some channel info {0} and {1}", 15.4, true);
+ *
+ * // This will log the following String:
+ * // "here is some channel info 15.4 and true"
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function warn(message:String, ... rest):void;
+}
+
+}
\ No newline at end of file
diff --git a/src/mx/logging/ILoggingTarget.as b/src/mx/logging/ILoggingTarget.as
new file mode 100644
index 00000000..9a11f983
--- /dev/null
+++ b/src/mx/logging/ILoggingTarget.as
@@ -0,0 +1,158 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.logging
+{
+
+/**
+ * All logger target implementations within the logging framework
+ * must implement this interface.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public interface ILoggingTarget
+{
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // filters
+ //----------------------------------
+
+ /**
+ * In addition to the level setting, filters are used to
+ * provide a psuedo-hierarchical mapping for processing only those events
+ * for a given category.
+ *
+ * Each logger belongs to a category.
+ * By convention these categories map to the fully qualified class name
+ * in which the logger is used.
+ * For example, a logger that is logging messages for the
+ * mx.rpc.soap.WebService class would use
+ * "mx.rpc.soap.WebService" as the parameter
+ * to the Log.getLogger() call.
+ * When messages are sent under this category only those targets that have
+ * a filter which matches that category will receive notification of those
+ * events.
+ * Filter expressions may include a wildcard match, indicated with an
+ * asterisk.
+ * The wildcard must be the right most character in the expression.
+ * For example: rpc~~, mx.~~, or ~~.
+ * If an invalid expression is specified a InvalidFilterError
+ * will be thrown.
+ * No spaces or any of the following characters are valid within a filter
+ * expression: []~$^&\/(){}<>+=`!#%?,:;'"@.
+ * var traceLogger:ILoggingTarget = new TraceTarget(); + * traceLogger.filters = [ "mx.rpc.~~", "mx.messaging.~~" ]; + * Log.addTarget(traceLogger); + *+ * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + function get filters():Array; + + /** + * @private + */ + function set filters(value:Array):void; + + //---------------------------------- + // level + //---------------------------------- + + /** + * Provides access to the level this target is currently set at. + * Value values are: + *
LogEventLevel.FATAL designates events that are very
+ * harmful and will eventually lead to application failureLogEventLevel.ERROR designates error events that might
+ * still allow the application to continue running.LogEventLevel.WARN designates events that could be
+ * harmful to the application operationLogEventLevel.INFO designates informational messages
+ * that highlight the progress of the application at
+ * coarse-grained level.LogEventLevel.DEBUG designates informational
+ * level messages that are fine grained and most helpful when
+ * debugging an application.LogEventLevel.ALL intended to force a target to
+ * process all messages.Note: This method is called by the framework + * and should not be called by you directly.
+ * + * @param logger The ILogger that this target listens to. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + function addLogger(logger:ILogger):void; + + /** + * Stops this target from receiving events from the specified logger. + * + *Note: This method is called by the framework + * and should not be called by you directly.
+ * + * @param logger The ILogger that this target ignores. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + function removeLogger(logger:ILogger):void; +} + +} diff --git a/src/mx/logging/Log.as b/src/mx/logging/Log.as new file mode 100644 index 00000000..97359616 --- /dev/null +++ b/src/mx/logging/Log.as @@ -0,0 +1,486 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2005-2007 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.logging +{ + +import mx.logging.errors.InvalidCategoryError; +//import mx.managers.ISystemManager; +//import mx.managers.SystemManager; +import mx.resources.IResourceManager; +import mx.resources.ResourceManager; + +[ResourceBundle("logging")] + +/** + * Provides pseudo-hierarchical logging capabilities with multiple format and + * output options. + * The log system consists of two major components, the logger and a target. + * You can use the logger to send information to a target. + * The target is responsible for formatting and general output of the log data. + *+ * Loggers are singleton instances created for a particular category of + * information. + * Typically, the category is the package name of the component + * that desires to log information. + * The category provides users the ability to specify what log information they + * are interested in. + * Multiple categories can be selected and combined with regular expressions. + * This allows for both broad and narrow logging information to be acquired. + * For example, you might be interested in all logging information under + * the "mx.messaging" and "mx.rpc" packages and want the output from these + * packages to be formatted as XML. + * To get the all of the logging information under the "mx.messaging" category + * including sub-packages and components a wildcard expression is required, such as + * "mx.messaging.~~". + * See the code example below for more details. + *
+ *Targets provide the output mechanism of the data being logged.
+ * This mechanism typically includes formatting, transmission, or storage, but
+ * can be anything possible under the VM.
+ * There are two targets provided: MiniDebugTarget and
+ * TraceTarget.
+ * Each of these writers take the current log information and "sends" it
+ * somewhere for display and/or storage.
+ * Targets also provide the specification of what log data to output.
+ *
+ * ...
+ * import mx.logging.targets.*;
+ * import mx.logging.*;
+ *
+ * private function initLogging():void {
+ * // Create a target.
+ * var logTarget:TraceTarget = new TraceTarget();
+ *
+ * // Log only messages for the classes in the mx.rpc.* and
+ * // mx.messaging packages.
+ * logTarget.filters=["mx.rpc.*","mx.messaging.*"];
+ *
+ * // Log all log levels.
+ * logTarget.level = LogEventLevel.ALL;
+ *
+ * // Add date, time, category, and log level to the output.
+ * logTarget.includeDate = true;
+ * logTarget.includeTime = true;
+ * logTarget.includeCategory = true;
+ * logTarget.includeLevel = true;
+ *
+ * // Begin logging.
+ * Log.addTarget(logTarget);
+ * }
+ * ...
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class Log
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Sentinal value for the target log level to indicate no logging.
+ */
+ private static var NONE:int = int.MAX_VALUE;
+
+ /**
+ * @private
+ * The most verbose supported log level among registered targets.
+ */
+ private static var _targetLevel:int = NONE;
+ // Initialize target level to a value out of range.
+
+ /**
+ * @private
+ * An associative Array of existing loggers keyed by category
+ */
+ private static var _loggers:Array;
+
+ /**
+ * @private
+ * Array of targets that should be searched any time
+ * a new logger is created.
+ */
+ private static var _targets:Array = [];
+
+ /**
+ * @private
+ * Storage for the resourceManager getter.
+ * This gets initialized on first access,
+ * not at static initialization time, in order to ensure
+ * that the Singleton registry has already been initialized.
+ */
+ private static var _resourceManager:IResourceManager;
+
+ /**
+ * @private
+ * A reference to the object which manages
+ * all of the application's localized resources.
+ * This is a singleton instance which implements
+ * the IResourceManager interface.
+ */
+ private static function get resourceManager():IResourceManager
+ {
+ if (!_resourceManager)
+ _resourceManager = ResourceManager.getInstance();
+
+ return _resourceManager;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Indicates whether a fatal level log event will be processed by a
+ * log target.
+ *
+ * @return true if a fatal level log event will be logged; otherwise false.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isFatal():Boolean
+ {
+ return (_targetLevel <= LogEventLevel.FATAL) ? true : false;
+ }
+
+ /**
+ * Indicates whether an error level log event will be processed by a
+ * log target.
+ *
+ * @return true if an error level log event will be logged; otherwise false.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isError():Boolean
+ {
+ return (_targetLevel <= LogEventLevel.ERROR) ? true : false;
+ }
+
+ /**
+ * Indicates whether a warn level log event will be processed by a
+ * log target.
+ *
+ * @return true if a warn level log event will be logged; otherwise false.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isWarn():Boolean
+ {
+ return (_targetLevel <= LogEventLevel.WARN) ? true : false;
+ }
+
+ /**
+ * Indicates whether an info level log event will be processed by a
+ * log target.
+ *
+ * @return true if an info level log event will be logged; otherwise false.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isInfo():Boolean
+ {
+ return (_targetLevel <= LogEventLevel.INFO) ? true : false;
+ }
+
+ /**
+ * Indicates whether a debug level log event will be processed by a
+ * log target.
+ *
+ * @return true if a debug level log event will be logged; otherwise false.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isDebug():Boolean
+ {
+ return (_targetLevel <= LogEventLevel.DEBUG) ? true : false;
+ }
+
+ /**
+ * Allows the specified target to begin receiving notification of log
+ * events.
+ *
+ * @param The specific target that should capture log events.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function addTarget(target:ILoggingTarget):void
+ {
+ if (target)
+ {
+ var filters:Array = target.filters;
+ var logger:ILogger;
+ // need to find what filters this target matches and set the specified
+ // target as a listener for that logger.
+ for (var i:String in _loggers)
+ {
+ if (categoryMatchInFilterList(i, filters))
+ target.addLogger(ILogger(_loggers[i]));
+ }
+ // if we found a match all is good, otherwise we need to
+ // put the target in a waiting queue in the event that a logger
+ // is created that this target cares about.
+ _targets.push(target);
+
+ if (_targetLevel == NONE)
+ _targetLevel = target.level
+ else if (target.level < _targetLevel)
+ _targetLevel = target.level;
+ }
+ else
+ {
+ var message:String = resourceManager.getString(
+ "logging", "invalidTarget");
+ throw new ArgumentError(message);
+ }
+ }
+
+ /**
+ * Stops the specified target from receiving notification of log
+ * events.
+ *
+ * @param The specific target that should capture log events.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function removeTarget(target:ILoggingTarget):void
+ {
+ if (target)
+ {
+ var filters:Array = target.filters;
+ var logger:ILogger;
+ // Disconnect this target from any matching loggers.
+ for (var i:String in _loggers)
+ {
+ if (categoryMatchInFilterList(i, filters))
+ {
+ target.removeLogger(ILogger(_loggers[i]));
+ }
+ }
+ // Remove the target.
+ for (var j:int = 0; j<_targets.length; j++)
+ {
+ if (target == _targets[j])
+ {
+ _targets.splice(j, 1);
+ j--;
+ }
+ }
+ resetTargetLevel();
+ }
+ else
+ {
+ var message:String = resourceManager.getString(
+ "logging", "invalidTarget");
+ throw new ArgumentError(message);
+ }
+ }
+
+ /**
+ * Returns the logger associated with the specified category.
+ * If the category given doesn't exist a new instance of a logger will be
+ * returned and associated with that category.
+ * Categories must be at least one character in length and may not contain
+ * any blanks or any of the following characters:
+ * []~$^&\/(){}<>+=`!#%?,:;'"@
+ * This method will throw an InvalidCategoryError if the
+ * category specified is malformed.
+ *
+ * @param category The category of the logger that should be returned.
+ *
+ * @return An instance of a logger object for the specified name.
+ * If the name doesn't exist, a new instance with the specified
+ * name is returned.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function getLogger(category:String):ILogger
+ {
+ checkCategory(category);
+ if (!_loggers)
+ _loggers = [];
+
+ // get the logger for the specified category or create one if it
+ // doesn't exist
+ var result:ILogger = _loggers[category];
+ if (result == null)
+ {
+ result = new LogLogger(category);
+ _loggers[category] = result;
+ }
+
+ // check to see if there are any targets waiting for this logger.
+ var target:ILoggingTarget;
+ for (var i:int = 0; i < _targets.length; i++)
+ {
+ target = ILoggingTarget(_targets[i]);
+ if (categoryMatchInFilterList(category, target.filters))
+ target.addLogger(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * This method removes all of the current loggers from the cache.
+ * Subsquent calls to the getLogger() method return new instances
+ * of loggers rather than any previous instances with the same category.
+ * This method is intended for use in debugging only.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function flush():void
+ {
+ _loggers = [];
+ _targets = [];
+ _targetLevel = NONE;
+ }
+
+ /**
+ * This method checks the specified string value for illegal characters.
+ *
+ * @param value The String to check for illegal characters.
+ * The following characters are not valid:
+ * []~$^&\/(){}<>+=`!#%?,:;'"@
+ * @return true if there are any illegal characters found,
+ * false otherwise
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function hasIllegalCharacters(value:String):Boolean
+ {
+ return value.search(/[\[\]\~\$\^\&\\(\)\{\}\+\?\/=`!@#%,:;'"<>\s]/) != -1;
+ }
+
+ // private members
+ /**
+ * This method checks that the specified category matches any of the filter
+ * expressions provided in the filters Array.
+ *
+ * @param category The category to match against
+ * @param filters A list of Strings to check category against.
+ * @return true if the specified category matches any of the
+ * filter expressions found in the filters list, false
+ * otherwise.
+ * @private
+ */
+ private static function categoryMatchInFilterList(category:String, filters:Array):Boolean
+ {
+ var result:Boolean = false;
+ var filter:String;
+ var index:int = -1;
+ for (var i:uint = 0; i < filters.length; i++)
+ {
+ filter = filters[i];
+ // first check to see if we need to do a partial match
+ // do we have an asterisk?
+ index = filter.indexOf("*");
+
+ if (index == 0)
+ return true;
+
+ index = index < 0 ? index = category.length : index -1;
+
+ if (category.substring(0, index) == filter.substring(0, index))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * This method will ensure that a valid category string has been specified.
+ * If the category is not valid an InvalidCategoryError will
+ * be thrown.
+ * Categories can not contain any blanks or any of the following characters:
+ * []`*~,!#$%^&()]{}+=\|'";?><./@ or be less than 1 character in length.
+ * @private
+ */
+ private static function checkCategory(category:String):void
+ {
+ var message:String;
+
+ if (category == null || category.length == 0)
+ {
+ message = resourceManager.getString(
+ "logging", "invalidLen");
+ throw new InvalidCategoryError(message);
+ }
+
+ if (hasIllegalCharacters(category) || (category.indexOf("*") != -1))
+ {
+ message = resourceManager.getString(
+ "logging", "invalidChars");
+ throw new InvalidCategoryError(message);
+ }
+ }
+
+ /**
+ * @private
+ * This method resets the Log's target level to the most verbose log level
+ * for the currently registered targets.
+ */
+ private static function resetTargetLevel():void
+ {
+ var minLevel:int = NONE;
+ for (var i:int = 0; i < _targets.length; i++)
+ {
+ if (minLevel == NONE || _targets[i].level < minLevel)
+ minLevel = _targets[i].level;
+ }
+ _targetLevel = minLevel;
+ }
+}
+
+}
diff --git a/src/mx/logging/LogEvent.as b/src/mx/logging/LogEvent.as
new file mode 100644
index 00000000..490dae48
--- /dev/null
+++ b/src/mx/logging/LogEvent.as
@@ -0,0 +1,221 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.logging
+{
+
+import flash.events.Event;
+
+/**
+ * Represents the log information for a single logging event.
+ * The loging system dispatches a single event each time a process requests
+ * information be logged.
+ * This event can be captured by any object for storage or formatting.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class LogEvent extends Event
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Event type constant; identifies a logging event.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const LOG:String = "log";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Returns a string value representing the level specified.
+ *
+ * @param The level a string is desired for.
+ *
+ * @return The level specified in English.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function getLevelString(value:uint):String
+ {
+ switch (value)
+ {
+ case LogEventLevel.INFO:
+ {
+ return "INFO";
+ }
+
+ case LogEventLevel.DEBUG:
+ {
+ return "DEBUG";
+ }
+
+ case LogEventLevel.ERROR:
+ {
+ return "ERROR";
+ }
+
+ case LogEventLevel.WARN:
+ {
+ return "WARN";
+ }
+
+ case LogEventLevel.FATAL:
+ {
+ return "FATAL";
+ }
+
+ case LogEventLevel.ALL:
+ {
+ return "ALL";
+ }
+ }
+
+ return "UNKNOWN";
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param msg String containing the log data.
+ *
+ * @param level The level for this log event.
+ * Valid values are:
+ * LogEventLevel.FATAL designates events that are very
+ * harmful and will eventually lead to application failureLogEventLevel.ERROR designates error events that might
+ * still allow the application to continue running.LogEventLevel.WARN designates events that could be
+ * harmful to the application operationLogEventLevel.INFO designates informational messages
+ * that highlight the progress of the application at
+ * coarse-grained level.LogEventLevel.DEBUG designates informational
+ * level messages that are fine grained and most helpful when
+ * debugging an application.LogEventLevel.ALL intended to force a target to
+ * process all messages.LogEventLogEventLevel.INFO designates informational messages
+ * that highlight the progress of the application at
+ * coarse-grained level.LogEventLevel.DEBUG designates informational
+ * level messages that are fine grained and most helpful when
+ * debugging an application.LogEventLevel.ERROR designates error events that might
+ * still allow the application to continue running.LogEventLevel.WARN designates events that could be
+ * harmful to the application operation.LogEventLevel.FATAL designates events that are very
+ * harmful and will eventually lead to application failure.level
+ * property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public final class LogEventLevel
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Designates events that are very
+ * harmful and will eventually lead to application failure.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const FATAL:int = 1000;
+
+ /**
+ * Designates error events that might
+ * still allow the application to continue running.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const ERROR:int = 8;
+
+ /**
+ * Designates events that could be
+ * harmful to the application operation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const WARN:int = 6;
+
+ /**
+ * Designates informational messages that
+ * highlight the progress of the application at coarse-grained level.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const INFO:int = 4;
+
+ /**
+ * Designates informational level
+ * messages that are fine grained and most helpful when debugging an
+ * application.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const DEBUG:int = 2;
+
+ /**
+ * Tells a target to process all messages.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static const ALL:int = 0;
+}
+
+}
diff --git a/src/mx/logging/LogLogger.as b/src/mx/logging/LogLogger.as
new file mode 100644
index 00000000..a9695c93
--- /dev/null
+++ b/src/mx/logging/LogLogger.as
@@ -0,0 +1,249 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.logging
+{
+
+import flash.events.EventDispatcher;
+//import mx.managers.ISystemManager;
+//import mx.managers.SystemManager;
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+
+[ResourceBundle("logging")]
+
+/**
+ * The logger that is used within the logging framework.
+ * This class dispatches events for each message logged using the log() method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class LogLogger extends EventDispatcher implements ILogger
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param category The category for which this log sends messages.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function LogLogger(category:String)
+ {
+ super();
+
+ _category = category;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Used for accessing localized Error messages.
+ */
+ private var resourceManager:IResourceManager =
+ ResourceManager.getInstance();
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // category
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the category property.
+ */
+ private var _category:String;
+
+ /**
+ * The category this logger send messages for.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get category():String
+ {
+ return _category;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function log(level:int, msg:String, ... rest):void
+ {
+ // we don't want to allow people to log messages at the
+ // Log.Level.ALL level, so throw a RTE if they do
+ if (level < LogEventLevel.DEBUG)
+ {
+ var message:String = resourceManager.getString(
+ "logging", "levelLimit");
+ throw new ArgumentError(message);
+ }
+
+ if (hasEventListener(LogEvent.LOG))
+ {
+ // replace all of the parameters in the msg string
+ for (var i:int = 0; i < rest.length; i++)
+ {
+ msg = msg.replace(new RegExp("\\{"+i+"\\}", "g"), rest[i]);
+ }
+
+ dispatchEvent(new LogEvent(msg, level));
+ }
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function debug(msg:String, ... rest):void
+ {
+ if (hasEventListener(LogEvent.LOG))
+ {
+ // replace all of the parameters in the msg string
+ for (var i:int = 0; i < rest.length; i++)
+ {
+ msg = msg.replace(new RegExp("\\{"+i+"\\}", "g"), rest[i]);
+ }
+
+ dispatchEvent(new LogEvent(msg, LogEventLevel.DEBUG));
+ }
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function error(msg:String, ... rest):void
+ {
+ if (hasEventListener(LogEvent.LOG))
+ {
+ // replace all of the parameters in the msg string
+ for (var i:int = 0; i < rest.length; i++)
+ {
+ msg = msg.replace(new RegExp("\\{"+i+"\\}", "g"), rest[i]);
+ }
+
+ dispatchEvent(new LogEvent(msg, LogEventLevel.ERROR));
+ }
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function fatal(msg:String, ... rest):void
+ {
+ if (hasEventListener(LogEvent.LOG))
+ {
+ // replace all of the parameters in the msg string
+ for (var i:int = 0; i < rest.length; i++)
+ {
+ msg = msg.replace(new RegExp("\\{"+i+"\\}", "g"), rest[i]);
+ }
+
+ dispatchEvent(new LogEvent(msg, LogEventLevel.FATAL));
+ }
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function info(msg:String, ... rest):void
+ {
+ if (hasEventListener(LogEvent.LOG))
+ {
+ // replace all of the parameters in the msg string
+ for (var i:int = 0; i < rest.length; i++)
+ {
+ msg = msg.replace(new RegExp("\\{"+i+"\\}", "g"), rest[i]);
+ }
+
+ dispatchEvent(new LogEvent(msg, LogEventLevel.INFO));
+ }
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function warn(msg:String, ... rest):void
+ {
+ if (hasEventListener(LogEvent.LOG))
+ {
+ // replace all of the parameters in the msg string
+ for (var i:int = 0; i < rest.length; i++)
+ {
+ msg = msg.replace(new RegExp("\\{"+i+"\\}", "g"), rest[i]);
+ }
+
+ dispatchEvent(new LogEvent(msg, LogEventLevel.WARN));
+ }
+ }
+}
+
+}
diff --git a/src/mx/logging/errors/InvalidCategoryError.as b/src/mx/logging/errors/InvalidCategoryError.as
new file mode 100644
index 00000000..8366100d
--- /dev/null
+++ b/src/mx/logging/errors/InvalidCategoryError.as
@@ -0,0 +1,77 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.logging.errors
+{
+
+/**
+ * This error is thrown when a category specified for a logger
+ * contains invalid characters or is malformed.
+ * This error is thrown by the following method:
+ * Log.getLogger() if a category specified
+ * is malformed.ILoggerTarget.filters if a filter expression
+ * in this listis malformed.Constructs an instance of a logger target that will format + * the message data on a single line.
+ * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function LineFormattedTarget() + { + super(); + + includeTime = false; + includeDate = false; + includeCategory = false; + includeLevel = false; + } + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // fieldSeparator + //---------------------------------- + + [Inspectable(category="General", defaultValue=" ")] + + /** + * The separator string to use between fields (the default is " ") + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public var fieldSeparator:String = " "; + + //---------------------------------- + // includeCategory + //---------------------------------- + + [Inspectable(category="General", defaultValue="false")] + + /** + * Indicates if the category for this target should added to the trace. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public var includeCategory:Boolean; + + //---------------------------------- + // includeDate + //---------------------------------- + + [Inspectable(category="General", defaultValue="false")] + + /** + * Indicates if the date should be added to the trace. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public var includeDate:Boolean; + + //---------------------------------- + // includeLevel + //---------------------------------- + + [Inspectable(category="General", defaultValue="false")] + + /** + * Indicates if the level for the event should added to the trace. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public var includeLevel:Boolean; + + //---------------------------------- + // includeTime + //---------------------------------- + + [Inspectable(category="General", defaultValue="false")] + + /** + * Indicates if the time should be added to the trace. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public var includeTime:Boolean; + + //-------------------------------------------------------------------------- + // + // Overridden methods + // + //-------------------------------------------------------------------------- + + /** + * This method handles aLogEvent from an associated logger.
+ * A target uses this method to translate the event into the appropriate
+ * format for transmission, storage, or display.
+ * This method is called only if the event's level is in range of the
+ * target's level.
+ *
+ * @param event The LogEvent handled by this method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ override public function logEvent(event:LogEvent):void
+ {
+ var date:String = ""
+ if (includeDate || includeTime)
+ {
+ var d:Date = new Date();
+ if (includeDate)
+ {
+ date = Number(d.getMonth() + 1).toString() + "/" +
+ d.getDate().toString() + "/" +
+ d.getFullYear() + fieldSeparator;
+ }
+ if (includeTime)
+ {
+ date += padTime(d.getHours()) + ":" +
+ padTime(d.getMinutes()) + ":" +
+ padTime(d.getSeconds()) + "." +
+ padTime(d.getMilliseconds(), true) + fieldSeparator;
+ }
+ }
+
+ var level:String = "";
+ if (includeLevel)
+ {
+ level = "[" + LogEvent.getLevelString(event.level) +
+ "]" + fieldSeparator;
+ }
+
+ var category:String = includeCategory ?
+ ILogger(event.target).category + fieldSeparator :
+ "";
+
+ internalLog(date + level + category + event.message);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private function padTime(num:Number, millis:Boolean = false):String
+ {
+ if (millis)
+ {
+ if (num < 10)
+ return "00" + num.toString();
+ else if (num < 100)
+ return "0" + num.toString();
+ else
+ return num.toString();
+ }
+ else
+ {
+ return num > 9 ? num.toString() : "0" + num.toString();
+ }
+ }
+
+ /**
+ * Descendants of this class should override this method to direct the
+ * specified message to the desired output.
+ *
+ * @param message String containing preprocessed log message which may
+ * include time, date, category, etc. based on property settings,
+ * such as includeDate, includeCategory,
+ * etc.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ mx_internal function internalLog(message:String):void
+ {
+ // override this method to perform the redirection to the desired output
+ }
+}
+
+}
diff --git a/src/mx/logging/targets/TraceTarget.as b/src/mx/logging/targets/TraceTarget.as
new file mode 100644
index 00000000..b7afcbba
--- /dev/null
+++ b/src/mx/logging/targets/TraceTarget.as
@@ -0,0 +1,84 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.logging.targets
+{
+
+import mx.core.mx_internal;
+
+use namespace mx_internal;
+
+/**
+ * Provides a logger target that uses the global trace() method to output log messages.
+ *
+ * To view trace() method output, you must be running the
+ * debugger version of Flash Player or AIR Debug Launcher.
The debugger version of Flash Player and AIR Debug Launcher send output from the trace() method
+ * to the flashlog.txt file. The default location of this file is the same directory as
+ * the mm.cfg file. You can customize the location of this file by using the TraceOutputFileName
+ * property in the mm.cfg file. You must also set TraceOutputFileEnable to 1 in your mm.cfg file.
Constructs an instance of a logger target that will send
+ * the log data to the global trace() method.
+ * All output will be directed to flashlog.txt by default.
trace().
+ * All output will be directed to flashlog.txt by default.
+ *
+ * @param message String containing preprocessed log message which may
+ * include time, date, category, etc. based on property settings,
+ * such as includeDate, includeCategory, etc.
+ */
+ override mx_internal function internalLog(message:String):void
+ {
+ trace(message);
+ }
+}
+
+}
diff --git a/src/mx/managers/systemClasses/ChildManager.as b/src/mx/managers/systemClasses/ChildManager.as
new file mode 100644
index 00000000..bc1f3d75
--- /dev/null
+++ b/src/mx/managers/systemClasses/ChildManager.as
@@ -0,0 +1,425 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2003-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.managers.systemClasses
+{
+
+import flash.display.DisplayObject;
+import flash.display.DisplayObjectContainer;
+import flash.display.InteractiveObject;
+import flash.events.IEventDispatcher;
+
+import mx.core.IFlexDisplayObject;
+import mx.core.IFlexModule;
+import mx.core.IFlexModuleFactory;
+import mx.core.IFontContextComponent;
+import mx.core.IInvalidating;
+import mx.core.IUIComponent;
+import mx.core.UIComponent;
+import mx.core.mx_internal;
+import mx.events.FlexEvent;
+import mx.managers.ILayoutManagerClient;
+import mx.managers.ISystemManager;
+import mx.managers.ISystemManagerChildManager;
+import mx.managers.SystemManager;
+import mx.messaging.config.LoaderConfig;
+import mx.preloaders.Preloader;
+import mx.styles.ISimpleStyleClient;
+import mx.styles.IStyleClient;
+import mx.utils.LoaderUtil;
+
+use namespace mx_internal;
+
+[ExcludeClass]
+
+public class ChildManager //implements ISystemManagerChildManager
+{
+ include "../../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+
+ public function ChildManager(systemManager:IFlexModuleFactory)
+ {
+ super();
+/*
+ if (systemManager is ISystemManager)
+ {
+ systemManager["childManager"] = this;
+ this.systemManager = ISystemManager(systemManager);
+ this.systemManager.registerImplementation("mx.managers::ISystemManagerChildManager", this);
+ }*/
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /*
+ private var systemManager:ISystemManager;
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods: Child management
+ //
+ //--------------------------------------------------------------------------
+
+
+ public function addingChild(child:DisplayObject):void
+ {
+ var newNestLevel:int = 1;
+
+ // non-top level system managers may not be able to reference their parent if
+ // they are a proxy for popups.
+ if (!topLevel && DisplayObject(systemManager).parent)
+ {
+ // non-topLevel SystemManagers are buried by Flash.display.Loader and
+ // other non-framework layers so we have to figure out the nestlevel
+ // by searching up the parent chain.
+ var obj:DisplayObjectContainer = DisplayObject(systemManager).parent.parent;
+ while (obj)
+ {
+ if (obj is ILayoutManagerClient)
+ {
+ newNestLevel = ILayoutManagerClient(obj).nestLevel + 1;
+ break;
+ }
+ obj = obj.parent;
+ }
+ }
+ nestLevel = newNestLevel;
+
+ if (child is IUIComponent)
+ IUIComponent(child).systemManager = systemManager;
+
+ // If the document property isn't already set on the child,
+ // set it to be the same as this component's document.
+ // The document setter will recursively set it on any
+ // descendants of the child that exist.
+ if (child is IUIComponent &&
+ !IUIComponent(child).document)
+ {
+ IUIComponent(child).document = systemManager.document;
+ }
+
+ // Set the moduleFactory to the child, but don't overwrite an existing moduleFactory.
+ if (child is IFlexModule && IFlexModule(child).moduleFactory == null)
+ IFlexModule(child).moduleFactory = systemManager;
+
+ // Set the font context in non-UIComponent children.
+ // UIComponent children use moduleFactory.
+ if (child is IFontContextComponent && !child is UIComponent &&
+ IFontContextComponent(child).fontContext == null)
+ IFontContextComponent(child).fontContext = systemManager;
+
+ // Set the nestLevel of the child to be one greater
+ // than the nestLevel of this component.
+ // The nestLevel setter will recursively set it on any
+ // descendants of the child that exist.
+ if (child is ILayoutManagerClient)
+ ILayoutManagerClient(child).nestLevel = nestLevel + 1;
+
+ if (child is InteractiveObject)
+ if (InteractiveObject(systemManager).doubleClickEnabled)
+ InteractiveObject(child).doubleClickEnabled = true;
+
+ if (child is IUIComponent)
+ IUIComponent(child).parentChanged(DisplayObjectContainer(systemManager));
+
+ // Sets up the inheritingStyles and nonInheritingStyles objects
+ // and their proto chains so that getStyle() works.
+ // If this object already has some children,
+ // then reinitialize the children's proto chains.
+ if (child is IStyleClient)
+ IStyleClient(child).regenerateStyleCache(true);
+
+ if (child is ISimpleStyleClient)
+ ISimpleStyleClient(child).styleChanged(null);
+
+ if (child is IStyleClient)
+ IStyleClient(child).notifyStyleChangeInChildren(null, true);
+
+ // Need to check to see if the child is an UIComponent
+ // without actually linking in the UIComponent class.
+ if (child is UIComponent)
+ UIComponent(child).initThemeColor();
+
+ // Inform the component that it's style properties
+ // have been fully initialized. Most components won't care,
+ // but some need to react to even this early change.
+ if (child is UIComponent)
+ UIComponent(child).stylesInitialized();
+ }
+
+
+ public function childAdded(child:DisplayObject):void
+ {
+ if (child.hasEventListener(FlexEvent.ADD))
+ child.dispatchEvent(new FlexEvent(FlexEvent.ADD));
+
+ if (child is IUIComponent)
+ IUIComponent(child).initialize(); // calls child.createChildren()
+ }
+
+
+ public function removingChild(child:DisplayObject):void
+ {
+ if (child.hasEventListener(FlexEvent.REMOVE))
+ child.dispatchEvent(new FlexEvent(FlexEvent.REMOVE));
+ }
+
+
+ public function childRemoved(child:DisplayObject):void
+ {
+ if (child is IUIComponent)
+ IUIComponent(child).parentChanged(null);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods: Styles
+ //
+ //--------------------------------------------------------------------------
+
+
+ public function regenerateStyleCache(recursive:Boolean):void
+ {
+ var foundTopLevelWindow:Boolean = false;
+
+ var n:int = systemManager.rawChildren.numChildren;
+ for (var i:int = 0; i < n; i++)
+ {
+ var child:IStyleClient =
+ systemManager.rawChildren.getChildAt(i) as IStyleClient;
+
+ if (child)
+ child.regenerateStyleCache(recursive);
+
+ if (isTopLevelWindow(DisplayObject(child)))
+ foundTopLevelWindow = true;
+
+ // Refetch numChildren because notifyStyleChangedInChildren()
+ // can add/delete a child and therefore change numChildren.
+ n = systemManager.rawChildren.numChildren;
+ }
+
+ // During startup the top level window isn't added
+ // to the child list until late into the startup sequence.
+ // Make sure we call regenerateStyleCache()
+ // on the top level window even if it isn't a child yet.
+ if (!foundTopLevelWindow && topLevelWindow is IStyleClient)
+ IStyleClient(topLevelWindow).regenerateStyleCache(recursive);
+ }
+
+
+ public function notifyStyleChangeInChildren(styleProp:String,
+ recursive:Boolean):void
+ {
+ var foundTopLevelWindow:Boolean = false;
+
+ var n:int = systemManager.rawChildren.numChildren;
+ for (var i:int = 0; i < n; i++)
+ {
+ var child:IStyleClient =
+ systemManager.rawChildren.getChildAt(i) as IStyleClient;
+
+ if (child)
+ {
+ child.styleChanged(styleProp);
+ child.notifyStyleChangeInChildren(styleProp, recursive);
+ }
+
+ if (isTopLevelWindow(DisplayObject(child)))
+ foundTopLevelWindow = true;
+
+ // Refetch numChildren because notifyStyleChangedInChildren()
+ // can add/delete a child and therefore change numChildren.
+ n = systemManager.rawChildren.numChildren;
+ }
+
+ // During startup the top level window isn't added
+ // to the child list until late into the startup sequence.
+ // Make sure we call notifyStyleChangeInChildren()
+ // on the top level window even if it isn't a child yet.
+ if (!foundTopLevelWindow && topLevelWindow is IStyleClient)
+ {
+ IStyleClient(topLevelWindow).styleChanged(styleProp);
+ IStyleClient(topLevelWindow).notifyStyleChangeInChildren(
+ styleProp, recursive);
+ }
+ }
+
+
+ public function initializeTopLevelWindow(width:Number, height:Number):void
+ {
+/*
+ CONFIG::performanceInstrumentation
+ {
+ var perfUtil:mx.utils.PerfUtil = mx.utils.PerfUtil.getInstance();
+ perfUtil.markTime("ChildManager.initializeTopLevelWindow().start");
+ perfUtil.markTime("SystemManager.create().start");
+ }
+*//*
+ var app:IUIComponent;
+ // Create a new instance of the toplevel class
+ systemManager.document = app = topLevelWindow = IUIComponent(systemManager.create());
+/*
+ CONFIG::performanceInstrumentation
+ {
+ perfUtil.markTime("SystemManager.create().end");
+ }
+*//*
+ if (systemManager.document)
+ {
+ // Add listener for the creationComplete event
+ IEventDispatcher(app).addEventListener(FlexEvent.CREATION_COMPLETE,
+ appCreationCompleteHandler);
+
+ // if somebody has set this in our applicationdomain hierarchy, don't overwrite it
+ if (!LoaderConfig._url)
+ {
+ LoaderConfig._url = LoaderUtil.normalizeURL(systemManager.loaderInfo);
+ LoaderConfig._parameters = systemManager.loaderInfo.parameters;
+ LoaderConfig._swfVersion = systemManager.loaderInfo.swfVersion;
+ }
+
+ IFlexDisplayObject(app).setActualSize(width, height);
+
+ // Wait for the app to finish its initialization sequence
+ // before doing an addChild().
+ // Otherwise, the measurement/layout code will cause the
+ // player to do a bunch of unnecessary screen repaints,
+ // which slows application startup time.
+
+ // Pass the application instance to the preloader.
+ // Note: preloader can be null when the user chooses
+ // Control > Play in the standalone player.
+ if (preloader)
+ preloader.registerApplication(app);
+
+ // The Application doesn't get added to the SystemManager in the standard way.
+ // We want to recursively create the entire application subtree and process
+ // it with the LayoutManager before putting the Application on the display list.
+ // So here we what would normally happen inside an override of addChild().
+ // Leter, when we actually attach the Application instance,
+ // we call super.addChild(), which is the bare player method.
+ addingChild(DisplayObject(app));
+/*
+ CONFIG::performanceInstrumentation
+ {
+ perfUtil.markTime("Application.createChildren().start");
+ }
+*//*
+ childAdded(DisplayObject(app)); // calls app.createChildren()
+/*
+ CONFIG::performanceInstrumentation
+ {
+ perfUtil.markTime("Application.createChildren().end");
+ }
+*//*
+ }
+ else
+ {
+ systemManager.document = this;
+ }
+/*
+ CONFIG::performanceInstrumentation
+ {
+ perfUtil.markTime("ChildManager.initializeTopLevelWindow().end");
+ }
+*//*
+ }
+
+
+ private function appCreationCompleteHandler(event:FlexEvent):void
+ {
+ if (!topLevel && DisplayObject(systemManager).parent)
+ {
+ var obj:DisplayObjectContainer = DisplayObject(systemManager).parent.parent;
+ while (obj)
+ {
+ if (obj is IInvalidating)
+ {
+ IInvalidating(obj).invalidateSize();
+ IInvalidating(obj).invalidateDisplayList();
+ return;
+ }
+ obj = obj.parent;
+ }
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods to implement SystemManager methods
+ //
+ // systemManager may be a SystemManager or WindowedSystemManager
+ // so we use the array access operertor to get at the methods/properties.
+ //
+ //--------------------------------------------------------------------------
+
+ private function isTopLevelWindow(object:DisplayObject):Boolean
+ {
+ return systemManager["isTopLevelWindow"](object);
+ }
+
+
+ private function get topLevel():Boolean
+ {
+ return systemManager["topLevel"];
+ }
+
+ private function set topLevel(topLevel:Boolean):void
+ {
+ systemManager["topLevel"] = topLevel;
+ }
+
+ private function get topLevelWindow():IUIComponent
+ {
+ return systemManager["topLevelWindow"];
+ }
+
+ private function set topLevelWindow(window:IUIComponent):void
+ {
+ systemManager["topLevelWindow"] = window;
+ }
+
+ private function get nestLevel():int
+ {
+ return systemManager["nestLevel"];
+ }
+
+ private function set nestLevel(level:int):void
+ {
+ systemManager["nestLevel"] = level;
+ }
+
+ private function get preloader():Preloader
+ {
+ return systemManager["preloader"];
+ }
+
+ private function set preloader(preloader:Preloader):void
+ {
+ systemManager["preloader"] = preloader;
+ } */
+}
+
+}
+
+
diff --git a/src/mx/modules/IModuleInfo.as b/src/mx/modules/IModuleInfo.as
new file mode 100644
index 00000000..f0c96dfb
--- /dev/null
+++ b/src/mx/modules/IModuleInfo.as
@@ -0,0 +1,320 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.modules
+{
+
+import flash.events.IEventDispatcher;
+import flash.system.ApplicationDomain;
+import flash.system.SecurityDomain;
+import flash.utils.ByteArray;
+import mx.core.IFlexModuleFactory;
+
+//--------------------------------------
+// Events
+//--------------------------------------
+
+/**
+ * Dispatched by the backing ModuleInfo if there was an error during
+ * module loading.
+ *
+ * @eventType mx.events.ModuleEvent.ERROR
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+[Event(name="error", type="mx.events.ModuleEvent")]
+
+/**
+ * Dispatched by the backing ModuleInfo at regular intervals
+ * while the module is being loaded.
+ *
+ * @eventType mx.events.ModuleEvent.PROGRESS
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+[Event(name="progress", type="mx.events.ModuleEvent")]
+
+/**
+ * Dispatched by the backing ModuleInfo once the module is sufficiently
+ * loaded to call the IModuleInfo.factory() method and the
+ * IFlexModuleFactory.create() method.
+ *
+ * @eventType mx.events.ModuleEvent.READY
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+[Event(name="ready", type="mx.events.ModuleEvent")]
+
+/**
+ * Dispatched by the backing ModuleInfo once the module is sufficiently
+ * loaded to call the IModuleInfo.factory() method and
+ * the IFlexModuleFactory.info() method.
+ *
+ * @eventType mx.events.ModuleEvent.SETUP
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+[Event(name="setup", type="mx.events.ModuleEvent")]
+
+/**
+ * Dispatched by the backing ModuleInfo when the module data is unloaded.
+ *
+ * @eventType mx.events.ModuleEvent.UNLOAD
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+[Event(name="unload", type="mx.events.ModuleEvent")]
+
+/**
+ * An interface that acts as a handle for a particular module.
+ * From this interface, the module status can be queried,
+ * its inner factory can be obtained, and it can be loaded or unloaded.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public interface IModuleInfo extends IEventDispatcher
+{
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // data
+ //----------------------------------
+
+ /**
+ * User data that can be associated with the singleton IModuleInfo
+ * for a given URL.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get data():Object;
+
+ /**
+ * @private
+ */
+ function set data(value:Object):void;
+
+ //----------------------------------
+ // error
+ //----------------------------------
+
+ /**
+ * A flag that is true if there was an error
+ * during module loading.
+ *
+ * This flag is true when the ModuleManager dispatches the
+ * ModuleEvent.ERROR event.
null after the
+ * ModuleEvent.SETUP event has been dispatched
+ * (or the IModuleInfo.setup() method returns true).
+ * At this point, the IFlexModuleFactory.info() method can be called.
+ * Once a ModuleEvent.READY event is dispatched
+ * (or the IModuleInfo.ready() method returns true),
+ * it is possible to call the IFlexModuleFactory.create() method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get factory():IFlexModuleFactory;
+
+ //----------------------------------
+ // loaded
+ //----------------------------------
+
+ /**
+ * A flag that is true if the load()
+ * method has been called on this module.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get loaded():Boolean;
+
+ //----------------------------------
+ // ready
+ //----------------------------------
+
+ /**
+ * A flag that is true if the module is sufficiently loaded
+ * to get a handle to its associated IFlexModuleFactory implementation
+ * and call its create() method.
+ *
+ * This flag is true when the ModuleManager dispatches the
+ * ModuleEvent.READY event.
true if the module is sufficiently loaded
+ * to get a handle to its associated IFlexModuleFactory implementation
+ * and call its info() method.
+ *
+ * This flag is true when the ModuleManager dispatches the
+ * ModuleEvent.SETUP event.
progress events as loading proceeds.
+ *
+ * @param applicationDomain The current application domain in which your code is executing.
+ *
+ * @param securityDomain The current security "sandbox".
+ *
+ * @param bytes A ByteArray object. The ByteArray is expected to contain
+ * the bytes of a SWF file that represents a compiled Module. The ByteArray
+ * object can be obtained by using the URLLoader class. If this parameter
+ * is specified the module will be loaded from the ByteArray. If this
+ * parameter is null the module will be loaded from the url specified in
+ * the url property.
+ *
+ * @param moduleFactory The moduleFactory of the caller. One use of the
+ * moduleFactory is to determine the parent style manager of the loaded
+ * module.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function load(applicationDomain:ApplicationDomain = null,
+ securityDomain:SecurityDomain = null,
+ bytes:ByteArray = null,
+ moduleFactory:IFlexModuleFactory = null):void;
+
+ /**
+ * Releases the current reference to the module.
+ * This does not unload the module unless there are no other
+ * open references to it and the ModuleManager is set up
+ * to have only a limited number of loaded modules.
+ *
+ * @see mx.modules.ModuleManager
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function release():void;
+
+ /**
+ * Unloads the module.
+ * Flash Player and AIR will not fully unload and garbage collect this module if
+ * there are any outstanding references to definitions inside the
+ * module.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function unload():void;
+
+ /**
+ * Publishes an interface to the ModuleManager. This allows late (or decoupled)
+ * subscriptions to factories with a String handle. Use a URL that starts with
+ * publish:// to reference factories that are published in this manner.
+ *
+ * @param factory The class that implements the module's IFlexModuleFactory interface.
+ *
+ * @see mx.modules.ModuleManager
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function publish(factory:IFlexModuleFactory):void;
+
+}
+
+}
diff --git a/src/mx/mxml/FlexReferences.as b/src/mx/mxml/FlexReferences.as
new file mode 100644
index 00000000..17fe8fb6
--- /dev/null
+++ b/src/mx/mxml/FlexReferences.as
@@ -0,0 +1,65 @@
+package mx.mxml
+{
+ /*
+ import mx.binding.ArrayElementWatcher;
+ import mx.binding.BindingManager;
+ import mx.binding.FunctionReturnWatcher;
+ import mx.binding.RepeaterComponentWatcher;
+ import mx.binding.RepeaterItemWatcher;
+ import mx.binding.StaticPropertyWatcher;
+ import mx.binding.XMLWatcher;
+ import mx.core.BitmapAsset;
+ import mx.core.ClassFactory;
+ import mx.core.DeferredInstanceFromClass;
+ import mx.core.FontAsset;
+ import mx.core.IStateClient2;
+ import mx.filters.IBitmapFilter;
+ import mx.states.AddItems;
+ import mx.states.IOverride;
+ import mx.states.SetProperty;
+ import mx.states.SetStyle;
+ import mx.states.State;
+ import mx.styles.CSSStyleDeclaration;
+ */
+ /**
+ * Pulls various Flex classes into the Reflex swc.
+ * These classes are not referenced by Reflex and are not required to build Reflex in Flash Pro or AS3 projects.
+ * They will not be pulled into you swf unless you use MXML. When using MXML (with MXMLC) these classes are sometimes
+ * pulled into projects automatically by the compiler. We make them available to the compiler here so that project setup does
+ * not require any outside Flex SDK references.
+ */
+ public class FlexReferences
+ {
+ /*
+ // binding
+ static private var bm:BindingManager;
+ static private var aw:ArrayElementWatcher;
+ static private var frw:FunctionReturnWatcher;
+ static private var rcw:RepeaterComponentWatcher;
+ static private var riw:RepeaterItemWatcher;
+ static private var spw:StaticPropertyWatcher;
+ static private var xw:XMLWatcher;
+
+ // core
+ static private var cf:ClassFactory;
+ static private var fa:FontAsset;
+ static private var ba:BitmapAsset;
+
+ // states & styles
+ static private var sc2:mx.core.IStateClient2;
+ static private var csd:CSSStyleDeclaration;
+
+ static private var bf:IBitmapFilter;
+ static private var difc:DeferredInstanceFromClass;
+ */
+ /*
+ //
+ static private var ai:AddItems;
+ static private var io:IOverride;
+ static private var sp:SetProperty;
+ static private var ss:SetStyle;
+ static private var st:State;
+ */
+
+ }
+}
\ No newline at end of file
diff --git a/src/mx/resources/IResourceBundle.as b/src/mx/resources/IResourceBundle.as
new file mode 100644
index 00000000..b3dadb93
--- /dev/null
+++ b/src/mx/resources/IResourceBundle.as
@@ -0,0 +1,248 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.resources
+{
+
+/**
+ * The IResourceBundle and IResourceManager interfaces work together
+ * to provide localization support for Flex applications.
+ *
+ * There are three main concepts involved in localization: + * locales, resources, and resource bundles.
+ * + *A locale specifies a language and a country
+ * for which your application has been localized.
+ * For example, the locale "en_US"
+ * specifies English as spoken in the United States.
+ * (See the mx.resources.Locale class for more information.)
A resource is a named value that is locale-dependent.
+ * For example, your application might have a resource
+ * whose name is "OPEN"
+ * and whose value for an English locale is "Open"
+ * but whose value for a French locale is "Ouvrir".
A resource bundle is a named group of resources
+ * whose values have been localized for a particular locale.
+ * A resource bundle is identified by the combination of its
+ * bundleName and its locale,
+ * and has a content Object that contains
+ * the name-value pairs for the bundle's resources.
The IResourceBundle interface represents a specific resource bundle.
+ * However, most applications will only need to use IResourceManager.
+ * A single ResourceManager object implementing this interface
+ * manages multiple resource bundles, possibly for multiple locales,
+ * and provides access to the resources that they contain.
+ * For example, you can retrieve a specific resource as a String by calling
+ * resourceManager.getString(bundleName, resourceName).
+ * By changing the localeChain property of the ResourceManager,
+ * you can change which resource bundles are searched for resource values.
Generally, you do not create resource bundles yourself;
+ * instead, they are usually compiled from ~~.properties files.
+ * A properties file named MyResources.properties
+ * produces a resource bundle with "MyResources"
+ * for its bundleName.
+ * You generally produce multiple versions of each properties file,
+ * one for each locale that your application supports.
Flex properties files are similar to Java properties files,
+ * except that they also support MXML's Embed()
+ * and ClassReference() directives.
+ * These directives work the same way in a properties file
+ * as they do in a CSS file, producing class references.
+ * Also, the encoding for Flex properties files
+ * is always assumed to be UTF-8.
The Flex framework's resources have been localized
+ * for U.S. English (the "en_US" locale) and
+ * for Japanese (the "ja_JP" locale).
+ * The framework resources are organized into multiple bundles
+ * corresponding to framework packages; for example, the "formatters"
+ * bundle is used by classes in the mx.formatters package.
+ * (There is also a "SharedResources" bundle for resources used by
+ * multiple packages.)
The properties files for the framework resources, + * such as formatters.properties, can be found in the + * frameworks/projects/framework/bundles/{locale}/src directories + * of the Flex SDK. + * Your applications normally link against the Flex framework + * as a precompiled library, framework.swc, + * in the frameworks/libs directory. + * This library has no resources in it. + * Instead, the framework resources have been compiled into separate + * resource bundle libraries such as framework_rb.swc. + * These are located in the frameworks/locales/{locale} directories + * and your application must also link in one or more of these.
+ * + *You are free to organize your application's own resources
+ * into whatever bundles you find convenient.
+ * If you localize your application for locales
+ * other than "en_US" and "ja_JP",
+ * you should localize the framework's properties files for those locales
+ * as well and compile additional resource bundle libaries for them.
When your application starts, the ResourceManager is automatically + * populated with whatever resource bundles were compiled + * into the application. + * If you create a code module, by default the resources that its classes + * need are compiled into the module. + * When the module is loaded into an application, any bundles that the + * application does not already have are added to the ResourceManager.
+ * + *You can compile "resource modules" that have only resources in them,
+ * and load them with the loadResourceModule() method
+ * of the ResourceManager.
+ * With resource modules, you can support multiple locales by loading
+ * the resources you need at run time rather than compiling them into
+ * your application.
Although the ResourceManager is normally populated with resource bundles
+ * that were compiled into your application or loaded from modules,
+ * you can also programmatically create resource bundles and add them
+ * to the ResourceManager yourself with the addResourceBundle()
+ * method.
"MyResources".
+ *
+ * This read-only property is set + * when a resource bundle is constructed.
+ * + *Resource bundles that are automatically created from compiled
+ * properties files have bundle names based on the names of those files.
+ * For example, a properties file named MyResources.properties
+ * will produce a resource bundle whose bundleName
+ * is "MyResources".
The ResourceManager can manage multiple bundles with the same
+ * bundleName as long as they have different values
+ * for their locale property.
In general, you should access resources by using IResourceManager
+ * methods such as getString(), rather than directly
+ * accessing them in a resource bundle.
+ * However, if you are programmatically creating your own
+ * resource bundles, you can initialize them with resources,
+ * as follows:
+ * var rb:IResourceBundle = new ResourceBundle("fr_FR", "MyResources");
+ * rb.content["LANGUAGE"] = "Francais";
+ * rb.content["GREETING"] = "Bonjour";
+ *
+ *
+ * When a resource bundle is produced by compiling a properties + * file, its resource values are either of type String or Class. + * For example, if the properties file contains
+ * + *
+ * LANGUAGE=English
+ * MINIMUM_AGE=18
+ * ENABLED=true
+ * LOGO=Embed("logo.png")
+ *
+ *
+ * then the value of the LANGUAGE resource
+ * is the String "English",
+ * the value of the MINIMUM_AGE resource
+ * is the String "18",
+ * the value of the ENABLED resource
+ * is the String "true",
+ * and the value of the LOGO resource
+ * is a Class that represents the embedded PNG file.
You can use IResourceManager methods such as getInt()
+ * and getBoolean() to convert resource strings like
+ * "18" and "true" into the type
+ * that your code expects.
"en_US" for U.S. English.
+ *
+ * This read-only property is set + * when a resource bundle is constructed.
+ * + *Resource bundles that are automatically created from compiled
+ * properties files have locales based on the
+ * -compiler.locale option of the mxmlc or compc compilers.
+ * For example, suppose that you compile your application with the option
+ * -compiler.locale=en_US,ja_JP and that you have specified
+ * -compiler.source-path=resources/{locale} so that
+ * your application's resources, located in
+ * resources/en_US/MyResources.properties and
+ * resources/ja_JP/MyResources.properties, are found.
+ * Then your application will have two resource bundles
+ * whose bundleName is "MyResources",
+ * one whose locale is "en_US"
+ * and one whose locale is "ja_JP".
There are three main concepts involved in localization: + * locales, resources, and resource bundles.
+ * + *A locale specifies a language and a country
+ * for which your application has been localized.
+ * For example, the locale "en_US"
+ * specifies English as spoken in the United States.
+ * (See the mx.resources.Locale class for more information.)
A resource is a named value that is locale-dependent.
+ * For example, your application might have a resource
+ * whose name is "OPEN"
+ * and whose value for an English locale is "Open"
+ * but whose value for a French locale is "Ouvrir".
A resource bundle is a named group of resources
+ * whose values have been localized for a particular locale.
+ * A resource bundle is identified by the combination of its
+ * bundleName and its locale,
+ * and has a content object that contains
+ * the name-value pairs for the bundle's resources.
+ * See the documentation for mx.resources.IResourceBundle
+ * for information about how you typically create resource
+ * bundles from properties files.
A single ResourceManager object implementing the IResourceManager
+ * interface manages multiple resource bundles, possibly for multiple
+ * locales, and provides access to the resources that they contain.
+ * For example, you can retrieve a specific resource as a String by calling
+ * resourceManager.getString(bundleName, resourceName).
All classes that extend UIComponent, Formatter, or Validator
+ * have a resourceManager property
+ * that provides a reference to the object implementing this interface.
+ * Other classes can call ResourceManager.getInstance()
+ * to obtain this object.
Resource retrieval methods such as getString()
+ * search for resources in the locales specified
+ * by the localeChain property.
+ * By changing this property, you can make your application
+ * suddenly use, for example, Japanese rather than English resources.
When your application starts, the ResourceManager is automatically + * populated with whatever resource bundles were compiled + * into the application. + * If you create a code module, by default the resources that its classes + * need are compiled into the module. + * When the module is loaded into an application, any bundles that the + * application does not already have are added to the ResourceManager.
+ * + *You can compile "resource modules" which have only resources in them,
+ * and load them with the loadResourceModule() method
+ * of IResourceManager.
+ * With resource modules, you can support multiple locales by loading
+ * the resources you need at run time rather than compiling them into
+ * your application.
Although the ResourceManager is normally populated with resource bundles
+ * that were compiled into your application or loaded from modules,
+ * you can also programmatically create resource bundles and add them
+ * to the ResourceManager yourself with the addResourceBundle()
+ * method.
[ "en_US" ],
+ * which specifies one or more locales to be searched for resources.
+ *
+ * When you call the ResourceManager methods getObject(),
+ * getString(), getStringArray(),
+ * getNumber(), getInt(),
+ * getUint(), getBoolean(), or
+ * getClass() to get the value of a resource,
+ * you specify a bundle name and a resource name,
+ * but not a locale.
+ * The ResourceManager starts with the first locale in the
+ * localeChain and looks for a ResourceBundle
+ * with the specified bundle name for that locale.
+ * If such a ResourceBundle exists, and the specified resource
+ * exists in it, then the value of that resource is returned.
+ * Otherwise, the ResourceManager proceeds on to the other
+ * locales in the localeChain.
This scheme makes it possible to have locales that do not
+ * necessarily contain a complete set of localized resources.
+ * For example, if you are localizing your application for
+ * Indian English rather than U.S. English, you need only
+ * supply resources for the en_IN locale in which the
+ * Indian spelling or usage differs from that in the U.S.,
+ * and then set the localeChain property
+ * to [ "en_IN", "en_US" ].
Many framework classes assume that they can always
+ * obtain, from some locale, the resources that they expect,
+ * and they will throw errors if they cannot do so.
+ * Therefore, you must ensure that the localeChain
+ * always contains a complete set of resources.
+ * Unless you have done a complete localization of all the
+ * framework's resources as well as your own application's
+ * resources, you can keep the "en_US" locale
+ * at the end of your localeChain to ensure this.
Setting this property causes the ResourceManager to dispatch
+ * a "change" Event.
Each call to this method returns a new event-dispatching object
+ * that you can use to learn how the loading is progressing
+ * and whether it completes successfully or results in an error.
+ * This object dispatches ResourceEvent.PROGRESS,
+ * ResourceEvent.COMPLETE, and
+ * ResourceEvent.ERROR events.
When the module has been loaded, the resource bundles
+ * are added to the ResourceManager, but the localeChain
+ * is left unchanged.
+ * If the update parameter is true,
+ * the update() method will be called.
update() method when the module finishes loading.
+ *
+ * @param applicationDomain The ApplicationDomain passed to the
+ * load() method of the IModuleInfo class
+ * that loads the resource module.
+ * This parameter is optional and defaults to null.
+ *
+ * @param securityDomain The SecurityDomain passed to the
+ * load() method of the IModuleInfo class
+ * that loads the resource module.
+ * This parameter is optional and defaults to null.
+ *
+ * @return An object that is associated with this particular load operation
+ * that dispatches ResourceEvent.PROGRESS,
+ * ResourceEvent.COMPLETE, and
+ * ResourceEvent.ERROR events.
+ *
+ * @see mx.events.ResourceEvent
+ * @see mx.resources.IResourceManager#update()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function loadResourceModule(url:String, update:Boolean = true,
+ applicationDomain:ApplicationDomain = null,
+ securityDomain:SecurityDomain = null):
+ IEventDispatcher;
+
+ /**
+ * Begins unloading a loaded resource module.
+ *
+ * When the module is unloaded, its resource bundles
+ * are removed from the ResourceManager, but the localeChain
+ * is left unchanged.
+ * If the update parameter is true,
+ * the update() method will be called.
update() method when the module finishes unloading.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function unloadResourceModule(url:String, update:Boolean = true):void;
+
+ /**
+ * Adds the specified ResourceBundle to the ResourceManager
+ * so that its resources can be accessed by ResourceManager
+ * methods such as getString().
+ *
+ * @param resourceBundle The resource bundle to be added.
+ * @param useWeakReference Determines if the ResourceManager
+ * keeps a weak reference to the resource bundle.
+ * If useWeakReference is true then the ResourceManager
+ * provides a weak reference to the resource bundle. When the
+ * caller chooses to use a weak reference it becomes the
+ * caller's responsibility to keep a hard reference the resource bundle
+ * so it is not garbaged collected prematurely. If useWeakReference is
+ * false, the ResourceManager keeps a hard reference to the resource
+ * bundle so it will not be garbage collected.
+ *
+ * When a Flex sub-application or module automatically adds its compiled
+ * resource bundles to the ResourceManager, it calls the addResourceBundle()
+ * with useWeakReference set to true, to avoid becoming pinned in memory.
+ * If you create resource bundles at runtime in a sub-application or
+ * module, you should do the same. You then need to hold on to these
+ * resource bundles with a hard reference to prevent them from being
+ * garbage collected.
getString().
+ *
+ * @param locale A locale string such as "en_US".
+ *
+ * @param bundleName A bundle name such as "MyResources".
+ *
+ * @see mx.resources.IResourceBundle
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function removeResourceBundle(locale:String, bundleName:String):void;
+
+ /**
+ * Removes all ResourceBundles for the specified locale
+ * from the ResourceManager so that their resources
+ * can no longer be accessed by ResourceManager methods
+ * such as getString().
+ *
+ * @param locale A locale string such as "en_US".
+ *
+ * @see mx.resources.IResourceBundle
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function removeResourceBundlesForLocale(locale:String):void;
+
+ /**
+ * Dispatches a change event from the
+ * ResourceManager.
+ *
+ * This causes binding expressions to re-evaluate
+ * if they involve the ResourceManager methods
+ * getObject(), getString(),
+ * getStringArray(), getNumber(),
+ * getInt(), getUint(),
+ * getBoolean(), or getClass().
This also causes the resourcesChanged() method
+ * of a UIComponent, Formatter, or Validator to execute.
+ * Many components implement this method to update
+ * their state based on the latest resources.
The order of locales in this array is not specified.
+ * + * @return An Array of locale Strings. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + function getLocales():Array /* of String */; + + /** + * Returns an Array of Strings specifying all locales for which + * ResourceBundle objects exist in the ResourceManager, + * ordered using user preferences as reported by + *Capabilities.language or
+ * Capabilities.languages.
+ *
+ * @return An Array of locale Strings.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getPreferredLocaleChain():Array /* of String */;
+
+ /**
+ * Returns an Array of Strings specifying the bundle names
+ * for all ResourceBundle objects that exist in the ResourceManager
+ * and that belong to the specified locale.
+ *
+ * The order of bundle names in this Array is not specified.
+ * + * @param locale A locale string such as"en_US".
+ *
+ * @return An Array of bundle names.
+ *
+ * @see mx.resources.IResourceBundle
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getBundleNamesForLocale(locale:String):Array /* of String */;
+
+ /**
+ * Returns a ResourceBundle with the specified locale
+ * and bundleName that has been previously added
+ * to the ResourceManager with addResourceBundle().
+ * If no such ResourceBundle exists, this method returns null.
+ *
+ * @param locale A locale string such as "en_US".
+ *
+ * @param bundleName A bundle name such as "MyResources".
+ *
+ * @return The ResourceBundle with the specified locale
+ * and bundleName if one exists; otherwise null.
+ *
+ * @see mx.resources.IResourceBundle
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getResourceBundle(locale:String,
+ bundleName:String):IResourceBundle;
+
+ /**
+ * Searches the locales in the localeChain
+ * for the specified resource and returns
+ * the first resource bundle in which it is found.
+ * If the resource isn't found, this method returns null.
+ *
+ * @param bundleName A bundle name such as "MyResources".
+ *
+ * @param resourceName The name of a resource in the resource bundle.
+ *
+ * @return The first ResourceBundle in the localeChain
+ * that contains the specified resource, or null.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function findResourceBundleWithResource(
+ bundleName:String,
+ resourceName:String):IResourceBundle;
+
+ [Bindable("change")]
+
+ /**
+ * Gets the value of a specified resource as an Object.
+ *
+ * The value is returned exactly as it is stored
+ * in the content Object of the ResourceBundle,
+ * with no conversion.
+ * If the resource was compiled from a properties files,
+ * the resource value in the content Object
+ * is always a String unless you used the Embed()
+ * or ClassReference() directive, in which case
+ * it is a Class.
+ * Use the getString(), getStringArray(),
+ * getNumber(), getInt()
+ * getUint(), getBoolean(), and
+ * getClass() methods to convert the value
+ * to more specific types.
If the specified resource is not found,
+ * this method returns undefined.
null to search all locales
+ * in the localeChain.
+ * This parameter is optional and defaults to null;
+ * you should seldom need to specify it.
+ *
+ * @return The resource value, exactly as it is stored
+ * in the content Object,
+ * or undefined if the resource is not found.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getObject(bundleName:String, resourceName:String,
+ locale:String = null):*;
+
+ [Bindable("change")]
+
+ /**
+ * Gets the value of a specified resource as a String,
+ * after substituting specified values for placeholders.
+ *
+ * This method calls getObject()
+ * and then casts the result to a String.
If a parameters Array is passed to this method,
+ * the parameters in it are converted to Strings
+ * and then substituted, in order, for the placeholders
+ * "{0}", "{1}", and so on, in the String
+ * before it is returned.
If the specified resource is not found,
+ * this method returns null.
toString() method
+ * before being substituted.
+ *
+ * @param locale A specific locale to be used for the lookup,
+ * or null to search all locales
+ * in the localeChain.
+ * This parameter is optional and defaults to null;
+ * you should seldom need to specify it.
+ *
+ * @return The resource value, as a String,
+ * or null if it is not found.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getString(bundleName:String, resourceName:String,
+ parameters:Array = null,
+ locale:String = null):String;
+
+ [Bindable("change")]
+
+ /**
+ * Gets the value of a specified resource as an Array of Strings.
+ *
+ * This method assumes that the resource value is a String
+ * containing a comma-separated list of items.
+ * It calls the getString() method, splits the String
+ * into items at the commas, and trims white space
+ * before and after each item.
+ * It is useful if you have written a line such as:
+ * COUNTRIES=India, China, Japan + *+ * + *
in a properties file and you want to obtain the value
+ * [ "India", "China", "Japan" ]
+ * rather than the value "India, China, Japan".
If the specified resource is not found,
+ * this method returns null.
null to search all locales
+ * in the localeChain.
+ * This parameter is optional and defaults to null;
+ * you should seldom need to specify it.
+ *
+ * @return The resource value, as an Array of Strings,
+ * or null if it is not found.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getStringArray(bundleName:String,
+ resourceName:String,
+ locale:String = null):Array /* of String */;
+
+ [Bindable("change")]
+
+ /**
+ * Gets the value of a specified resource as a Number.
+ *
+ * This method calls getObject()
+ * and casts the result to a Number.
+ * It is useful if you have written a line such as:
+ * LONGITUDE=170.3 + *+ * + *
in a properties file and want to obtain the value
+ * 170.3 rather than "170.3".
If the specified resource is not found,
+ * this method returns NaN.
null to search all locales
+ * in the localeChain.
+ * This parameter is optional and defaults to null;
+ * you should seldom need to specify it.
+ *
+ * @return The resource value, as a Number,
+ * or NaN if it is not found.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getNumber(bundleName:String, resourceName:String,
+ locale:String = null):Number;
+
+ [Bindable("change")]
+
+ /**
+ * Gets the value of a specified resource as an int.
+ *
+ * This method calls getObject()
+ * and casts the result to an int.
+ * It is useful if you have written a line such as:
+ * MINIMUM=5 + *+ * + *
in a properties file and want to obtain the value
+ * 5 rather than "5".
If the specified resource is not found, + * this method returns 0.
+ * + * @param bundleName The name of a resource bundle. + * + * @param resourceName The name of a resource in the resource bundle. + * + * @param locale A specific locale to be used for the lookup, + * ornull to search all locales
+ * in the localeChain.
+ * This parameter is optional and defaults to null;
+ * you should seldom need to specify it.
+ *
+ * @return The resource value, as an int,
+ * or 0 if it is not found.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getInt(bundleName:String, resourceName:String,
+ locale:String = null):int;
+
+ [Bindable("change")]
+
+ /**
+ * Gets the value of a specified resource as a uint.
+ *
+ * This method calls the getObject() method
+ * and casts the result to a uint.
+ * It is useful if you have written a line such as:
+ * MINIMUM=5 + *+ * + *
in a properties file and want to obtain the value
+ * 5 rather than "5".
If the specified resource is not found, + * this method returns 0.
+ * + * @param bundleName The name of a resource bundle. + * + * @param resourceName The name of a resource in the resource bundle. + * + * @param locale A specific locale to be used for the lookup, + * ornull to search all locales
+ * in the localeChain.
+ * This parameter is optional and defaults to null;
+ * you should seldom need to specify it.
+ *
+ * @return The resource value, as a uint,
+ * or 0 if it is not found.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getUint(bundleName:String, resourceName:String,
+ locale:String = null):uint;
+
+ [Bindable("change")]
+
+ /**
+ * Gets the value of a specified resource as a Boolean.
+ *
+ * This method first calls getString()
+ * and converts the result to lowercase.
+ * It then returns true
+ * if the result was "true".
+ * and false otherwise.
If the specified resource is not found,
+ * this method returns false.
null to search all locales
+ * in the localeChain.
+ * This parameter is optional and defaults to null;
+ * you should seldom need to specify it.
+ *
+ * @return The resource value, as a Boolean,
+ * or false if it is not found.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getBoolean(bundleName:String, resourceName:String,
+ locale:String = null):Boolean;
+
+ [Bindable("change")]
+
+ /**
+ * Gets the value of a specified resource as a Class.
+ *
+ * This method calls getObject()
+ * and coerces it to type Class using the as operator.
+ * The result will be null if the resource value
+ * was not a class reference.
+ * It is useful if you have written a lines such as
+ * IMAGE=Embed("image.jpg")
+ * BUTTON_SKIN=ClassReference("skins.ButtonSkin_en_US")
+ *
+ *
+ * in a properties file and want to obtain
+ * the Class that the Embed()
+ * or ClassReference() directive produced.
If the specified resource is not found,
+ * this method returns null.
null to search all locales
+ * in the localeChain.
+ * This parameter is optional and defaults to null;
+ * you should seldom need to specify it.
+ *
+ * @return The resource value, as a Class,
+ * or null if it is not found.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getClass(bundleName:String, resourceName:String,
+ locale:String = null):Class;
+
+ /**
+ * Creates instances of all ResourceBundle subclasses that were compiled into the SWF
+ * and adds them to the ResourceManager.
+ *
+ * For example, if the locales parameter is [ "en_US", "ja_JP" ]
+ * and the bundleNames parameter is [ "core", "controls" ],
+ * then four resource bundles will be installed.
This method is used only by classes that implement the IFlexModuleFactory interface.
+ * + * @param applicationDomain The ApplicationDomain that is used to look up the resource bundle + * classes by name. + * + * @param locales An Array of Strings that specify the locales for which the SWF was compiled. + * + * @param bundleNames An Array of Strings that specify the names of the resource bundles + * that were compiled into the SWF. + * + * @param useWeakReference A flag that specifyies whether the resource bundles should be + * intalled into the ResourceManager using a weak reference. + * + * @return An Array of the ResourceBundle instances that were created + * and added to the ResourceManager. + * + * @see mx.core.IFlexModuleFactory + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + function installCompiledResourceBundles( + applicationDomain:ApplicationDomain, + locales:Array /* of String */, + bundleNames:Array /* of String */, + useWeakReference:Boolean = false):Array; + + /** + * Initializes thelocaleChain property of the ResourceManager
+ * using an algorithm that compares the operating system's list of user-preferred
+ * locales with the list of locales available in the SWF.
+ *
+ * For example, if the user has indicated in the operating system that she
+ * prefers French, and the SWF was compiled for the locales en_US, fr_FR, and de_DE,
+ * then the localeChain will be set so that the first locale in it
+ * is fr_FR.
This method is used only by classes that implement the IFlexModuleFactory interface.
+ * + * @param compiledLocales An Array of Strings specifying the locales + * for which the SWF was compiled. + * + * @see mx.core.IFlexModuleFactory + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + function initializeLocaleChain(compiledLocales:Array):void; +} + +} diff --git a/src/mx/resources/IResourceModule.as b/src/mx/resources/IResourceModule.as new file mode 100644 index 00000000..5c993950 --- /dev/null +++ b/src/mx/resources/IResourceModule.as @@ -0,0 +1,45 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2007 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.resources +{ + +[ExcludeClass] + +/** + * @private + * When the MXML compiler compiles a resource module, the class + * that it autogenerates to represent the module implements this interface. + */ +public interface IResourceModule +{ + //-------------------------------------------------------------------------- + // + // Methods + // + //-------------------------------------------------------------------------- + + /** + * An Array of ResourceBundle instances, containing one for each + * of the resource bundle classes in this resource module. + * + *The order of ResourceBundle instances in this Array + * is not specified.
+ * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + function get resourceBundles():Array /* of ResourceBundle */; +} + +} diff --git a/src/mx/resources/Locale.as b/src/mx/resources/Locale.as new file mode 100644 index 00000000..604ab9c5 --- /dev/null +++ b/src/mx/resources/Locale.as @@ -0,0 +1,228 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2005-2007 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.resources +{ + +import mx.managers.ISystemManager; + +/** + * The Locale class can be used to parse a locale String such as"en_US_MAC"
+ * into its three parts: a language code, a country code, and a variant.
+ *
+ * The localization APIs in the IResourceManager and IResourceBundle + * interfaces use locale Strings rather than Locale instances, + * so this class is seldom used in an application.
+ * + * @see mx.resources.IResourceBundle + * @see mx.resources.IResourceManager + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class Locale +{ + include "../core/Version.as"; + + //-------------------------------------------------------------------------- + // + // Class variables + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + private static var currentLocale:Locale; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @param localeString A 1-, 2-, or 3-part locale String, + * such as"en", "en_US", or "en_US_MAC".
+ * The parts are separated by underscore characters.
+ * The first part is a two-letter lowercase language code
+ * as defined by ISO-639, such as "en" for English.
+ * The second part is a two-letter uppercase country code
+ * as defined by ISO-3166, such as "US" for the United States.
+ * The third part is a variant String, which can be used
+ * to optionally distinguish multiple locales for the same language and country.
+ * It is sometimes used to indicate the operating system
+ * that the locale should be used with, such as "MAC", "WIN", or "UNIX".
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function Locale(localeString:String)
+ {
+ super();
+
+ this.localeString = localeString;
+
+ var parts:Array = localeString.split("_");
+
+ if (parts.length > 0)
+ _language = parts[0];
+
+ if (parts.length > 1)
+ _country = parts[1];
+
+ if (parts.length > 2)
+ _variant = parts.slice(2).join("_");
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private var localeString:String;
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // language
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the language property.
+ */
+ private var _language:String;
+
+ [Inspectable(category="General", defaultValue="null")]
+
+ /**
+ * The language code of this Locale instance. [Read-Only]
+ *
+ *
+ * var locale:Locale = new Locale("en_US_MAC");
+ * trace(locale.language); // outputs "en"
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get language():String
+ {
+ return _language;
+ }
+
+ //----------------------------------
+ // country
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the country property.
+ */
+ private var _country:String;
+
+ [Inspectable(category="General", defaultValue="null")]
+
+ /**
+ * The country code of this Locale instance. [Read-Only]
+ *
+ *
+ * var locale:Locale = new Locale("en_US_MAC");
+ * trace(locale.country); // outputs "US"
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get country():String
+ {
+ return _country
+ }
+
+ //----------------------------------
+ // variant
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the variant property.
+ */
+ private var _variant:String;
+
+ [Inspectable(category="General", defaultValue="null")]
+
+ /**
+ * The variant part of this Locale instance. [Read-Only]
+ *
+ *
+ * var locale:Locale = new Locale("en_US_MAC");
+ * trace(locale.variant); // outputs "MAC"
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get variant():String
+ {
+ return _variant;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Returns the locale String that was used to construct
+ * this Locale instance. For example:
+ *
+ *
+ * var locale:Locale = new Locale("en_US_MAC");
+ * trace(locale.toString()); // outputs "en_US_MAC"
+ *
+ *
+ * @return Returns the locale String that was used to
+ * construct this Locale instance.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function toString():String
+ {
+ return localeString;
+ }
+}
+
+}
diff --git a/src/mx/resources/LocaleSorter.as b/src/mx/resources/LocaleSorter.as
new file mode 100644
index 00000000..297c6c56
--- /dev/null
+++ b/src/mx/resources/LocaleSorter.as
@@ -0,0 +1,1040 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.resources
+{
+
+[ExcludeClass]
+
+/**
+ * @private
+ * The APIs of the LocaleSorter class provides the sorting functionality
+ * of application locales against system preferences.
+ */
+public class LocaleSorter
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Sorts a list of locales using the order specified
+ * by the user preferences.
+ *
+ * @param appLocales An Array of locales supported by the application.
+ *
+ * @param systemPreferences The locale chain of user-preferred locales.
+ *
+ * @param ultimateFallbackLocale The ultimate fallback locale
+ * that will be used when no locale from systemPreference matches
+ * a locale from application supported locale list.
+ *
+ * @param addAll When true, adds all the non-matching locales
+ * at the end of the result list preserving the given order.
+ *
+ * @return A locale chain that matches user preferences order.
+ */
+ public static function sortLocalesByPreference(
+ appLocales:Array, systemPreferences:Array,
+ ultimateFallbackLocale:String = null,
+ addAll:Boolean = false):Array
+ {
+ var result:Array = [];
+
+ var hasLocale:Object = {};
+
+ var i:int;
+ var j:int;
+ var k:int;
+ var l:int;
+ var locale:String;
+
+ var locales:Array = trimAndNormalize(appLocales);
+ var preferenceLocales:Array = trimAndNormalize(systemPreferences);
+
+ addUltimateFallbackLocale(preferenceLocales, ultimateFallbackLocale);
+
+ // For better performance, save the locales in a lookup table.
+ for (j = 0; j < locales.length; j++)
+ {
+ hasLocale[locales[j]] = j;
+ }
+
+ function promote(locale:String):void
+ {
+ if (typeof hasLocale[locale] != "undefined")
+ {
+ result.push(appLocales[hasLocale[locale]]);
+ delete hasLocale[locale];
+ }
+ }
+
+ for (i = 0, l = preferenceLocales.length; i < l; i++)
+ {
+ var plocale:LocaleID = LocaleID.fromString(preferenceLocales[i]);
+
+ // Step 1: Promote the perfect match.
+ promote(preferenceLocales[i]);
+
+ promote(plocale.toString());
+
+ // Step 2: Promote the parent chain.
+ while (plocale.transformToParent())
+ {
+ promote(plocale.toString());
+ }
+
+ // Parse it again.
+ plocale = LocaleID.fromString(preferenceLocales[i]);
+
+ // Step 3: Promote the order of siblings from preferenceLocales.
+ for (j = 0; j < l; j++)
+ {
+ locale = preferenceLocales[j];
+ if (plocale.isSiblingOf(LocaleID.fromString(locale)))
+ promote(locale);
+ }
+
+ // Step 4: Promote all remaining siblings
+ // (aka not in preferenceLocales)
+ // eg. push en_UK after en_US and en if the user
+ // doesn't have en_UK in the preference list
+ for (j = 0, k = locales.length; j < k; j++)
+ {
+ locale = locales[j];
+ if (plocale.isSiblingOf(LocaleID.fromString(locale)))
+ promote(locale);
+ }
+ }
+
+ if (addAll)
+ {
+ // Check what locales are not already loaded
+ // and push them preserving the order.
+ for (j = 0, k = locales.length; j < k; j++)
+ {
+ promote(locales[j]);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * @private
+ */
+ private static function trimAndNormalize(list:Array):Array
+ {
+ var resultList:Array = [];
+
+ for (var i:int = 0; i < list.length; i++)
+ {
+ resultList.push(normalizeLocale(list[i]));
+ }
+
+ return resultList;
+ }
+
+ /**
+ * @private
+ */
+ private static function normalizeLocale(locale:String):String
+ {
+ return locale.toLowerCase().replace(/-/g, "_");
+ }
+
+ /**
+ * @private
+ */
+ private static function addUltimateFallbackLocale(
+ preferenceLocales:Array,
+ ultimateFallbackLocale:String):void
+ {
+ if (ultimateFallbackLocale != null && ultimateFallbackLocale != "")
+ {
+ var locale:String = normalizeLocale(ultimateFallbackLocale);
+
+ if (preferenceLocales.indexOf(locale) == -1)
+ {
+ // Add the locale to the end of the chain.
+ preferenceLocales.push(locale);
+ }
+ }
+ }
+}
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Helper class: LocaleID
+//
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @private
+ * The APIs of the internal LocaleID class parse a locale string
+ * according to:
+ * RFC 4646: http://www.ietf.org/rfc/rfc4646.txt
+ * RFC 4647: http://www.ietf.org/rfc/rfc4647.txt
+ * IANA Language Subtag Registry:
+ * http://www.iana.org/assignments/language-subtag-registry
+ */
+class LocaleID
+{
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ public static const STATE_PRIMARY_LANGUAGE:int = 0;
+
+ /**
+ * @private
+ */
+ public static const STATE_EXTENDED_LANGUAGES:int = 1;
+
+ /**
+ * @private
+ */
+ public static const STATE_SCRIPT:int = 2;
+
+ /**
+ * @private
+ */
+ public static const STATE_REGION:int = 3;
+
+ /**
+ * @private
+ */
+ public static const STATE_VARIANTS:int = 4;
+
+ /**
+ * @private
+ */
+ public static const STATE_EXTENSIONS:int = 5;
+
+ /**
+ * @private
+ */
+ public static const STATE_PRIVATES:int = 6;
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private static function appendElements(dest:Array, src:Array):void
+ {
+ for (var i:uint = 0, argc:uint = src.length; i < argc; i++)
+ {
+ dest.push(src[i]);
+ }
+ }
+
+ /**
+ * @private
+ */
+ public static function fromString(str:String):LocaleID
+ {
+ var localeID:LocaleID = new LocaleID();
+
+ var state:int = STATE_PRIMARY_LANGUAGE;
+ var subtags:Array = str.replace(/-/g, '_').split('_');
+
+ var last_extension:Array;
+
+ for (var i:int = 0, l:int = subtags.length; i < l; i++)
+ {
+ var subtag:String = subtags[i].toLowerCase();
+
+ if (state == STATE_PRIMARY_LANGUAGE)
+ {
+ if (subtag == "x")
+ {
+ localeID.privateLangs = true;
+ // not used in our implementation,
+ // but makes the tag private
+ }
+ else if (subtag == "i")
+ {
+ localeID.lang += "i-";
+ // and wait the next subtag
+ // to complete the language name
+ }
+ else
+ {
+ localeID.lang += subtag;
+ state = STATE_EXTENDED_LANGUAGES;
+ }
+ }
+ else
+ {
+ // looking for:
+ // an extended language - 3 chars
+ // a script - 4 chars
+ // a region - 2-3 chars
+ // a variant - alpha with at least 5 chars
+ // or numeric with at least 4 chars
+ // an extension/private singleton - 1 char
+
+ var subtag_length:int = subtag.length;
+ if (subtag_length == 0)
+ continue; // skip zero-lengthed subtags
+
+ var firstChar:String = subtag.charAt(0).toLowerCase();
+
+ if (state <= STATE_EXTENDED_LANGUAGES &&
+ subtag_length == 3)
+ {
+ localeID.extended_langs.push(subtag);
+ if (localeID.extended_langs.length == 3)
+ {
+ // Allow a maximum of 3 extended langs.
+ state = STATE_SCRIPT;
+ }
+ }
+ else if (state <= STATE_SCRIPT &&
+ subtag_length == 4)
+ {
+ localeID.script = subtag;
+ state = STATE_REGION;
+ }
+ else if (state <= STATE_REGION &&
+ (subtag_length == 2 || subtag_length == 3))
+ {
+ localeID.region = subtag;
+ state = STATE_VARIANTS;
+ }
+ else if (state <= STATE_VARIANTS &&
+ ((firstChar >= "a" && firstChar <= "z" &&
+ subtag_length >= 5) ||
+ (firstChar >= "0" && firstChar <= "9" &&
+ subtag_length >= 4)))
+ {
+ // variant
+ localeID.variants.push(subtag);
+ state = STATE_VARIANTS;
+ }
+ else if (state < STATE_PRIVATES &&
+ subtag_length == 1)
+ {
+ // singleton
+ if (subtag == "x")
+ {
+ state = STATE_PRIVATES;
+ last_extension = localeID.privates;
+ }
+ else
+ {
+ state = STATE_EXTENSIONS;
+ last_extension = localeID.extensions[subtag] || [];
+ localeID.extensions[subtag] = last_extension;
+ }
+ }
+ else if (state >= STATE_EXTENSIONS)
+ {
+ last_extension.push(subtag);
+ }
+ }
+ }
+
+ localeID.canonicalize();
+
+ return localeID;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function LocaleID()
+ {
+ super();
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private var lang:String = "";
+
+ /**
+ * @private
+ */
+ private var script:String = "";
+
+ /**
+ * @private
+ */
+ private var region:String = "";
+
+ /**
+ * @private
+ */
+ private var extended_langs:Array = [];
+
+ /**
+ * @private
+ */
+ private var variants:Array = [];
+
+ /**
+ * @private
+ */
+ private var extensions:Object = {};
+
+ /**
+ * @private
+ */
+ private var privates:Array = [];
+
+ /**
+ * @private
+ */
+ private var privateLangs:Boolean = false;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ public function canonicalize():void
+ {
+ for (var i:String in extensions)
+ {
+ if (extensions.hasOwnProperty(i))
+ {
+ // Also clear zero length extensions.
+ if (extensions[i].length == 0)
+ delete extensions[i];
+ else
+ extensions[i] = extensions[i].sort();
+ }
+ }
+
+ extended_langs = extended_langs.sort();
+ variants = variants.sort();
+ privates = privates.sort();
+
+ if (script == "")
+ script = LocaleRegistry.getScriptByLang(lang);
+
+ // Still no script, check the region.
+ if (script == "" && region != "")
+ script = LocaleRegistry.getScriptByLangAndRegion(lang, region);
+
+ if (region == "" && script != "")
+ {
+ region = LocaleRegistry.getDefaultRegionForLangAndScript(
+ lang, script);
+ }
+ }
+
+ /**
+ * @private
+ */
+ public function toString():String
+ {
+ var stack:Array = [ lang ];
+
+ appendElements(stack, extended_langs);
+
+ if (script != "")
+ stack.push(script);
+
+ if (region != "")
+ stack.push(region);
+
+ appendElements(stack, variants);
+
+ for (var i:String in extensions)
+ {
+ if (extensions.hasOwnProperty(i))
+ {
+ stack.push(i);
+ appendElements(stack, extensions[i]);
+ }
+ }
+
+ if (privates.length > 0)
+ {
+ stack.push("x");
+ appendElements(stack, privates);
+ }
+
+ return stack.join("_");
+ }
+
+ /**
+ * @private
+ */
+ public function equals(locale:LocaleID):Boolean
+ {
+ return toString() == locale.toString();
+ }
+
+ /**
+ * @private
+ */
+ public function isSiblingOf(other:LocaleID):Boolean
+ {
+ return lang == other.lang && script == other.script;
+ }
+
+ /**
+ * @private
+ */
+ public function transformToParent():Boolean
+ {
+ if (privates.length > 0)
+ {
+ privates.splice(privates.length - 1, 1);
+ return true;
+ }
+
+ var lastExtensionName:String = null;
+ for (var i:String in extensions)
+ {
+ if (extensions.hasOwnProperty(i))
+ lastExtensionName = i;
+ }
+
+ if (lastExtensionName)
+ {
+ var lastExtension:Array = extensions[lastExtensionName];
+ if (lastExtension.length == 1)
+ {
+ delete extensions[lastExtensionName];
+ return true;
+ }
+ lastExtension.splice(lastExtension.length - 1, 1);
+ return true;
+ }
+
+ if (variants.length > 0)
+ {
+ variants.splice(variants.length - 1, 1);
+ return true;
+ }
+
+ if (script != "")
+ {
+ // Check if we can suppress the script.
+ if (LocaleRegistry.getScriptByLang(lang) != "")
+ {
+ script = "";
+ return true;
+ }
+ else if (region == "")
+ {
+ // Maybe the default region can suppress the script.
+ var defaultRegion:String =
+ LocaleRegistry.getDefaultRegionForLangAndScript(
+ lang, script);
+ if (defaultRegion != "")
+ {
+ region = defaultRegion;
+ script = "";
+ return true;
+ }
+ }
+ }
+
+ if (region != "")
+ {
+ if (!(script == "" && LocaleRegistry.getScriptByLang(lang) == ""))
+ {
+ region = "";
+ return true;
+ }
+ }
+
+ if (extended_langs.length > 0)
+ {
+ extended_langs.splice(extended_langs.length - 1, 1);
+ return true;
+ }
+
+ return false;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Helper class: LocaleRegistry
+//
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @private
+ */
+class LocaleRegistry
+{
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * A list of codes representing writing systems, in arbitrary order.
+ * For example, "latn" represents the Latin alphabet, used for
+ * writing languages such as English, French, Indonesian, and Swahili,
+ * and "arab" represents the Arabic script, used for writing
+ * Arabic, Persian, Pashto, and Urdu.
+ */
+ private static const SCRIPTS:Array =
+ [
+ "", // 0
+ "latn", // 1 Latin
+ "ethi", // 2 Ethiopian
+ "arab", // 3 Arabic
+ "beng", // 4 Bengali
+ "cyrl", // 5 Cyrillic
+ "thaa", // 6 Thaana
+ "tibt", // 7 Tibetan
+ "grek", // 8 Greek
+ "gujr", // 9 Gujarati
+ "hebr", // 10 Hebrew
+ "deva", // 11 Devanagari
+ "armn", // 12 Armenian
+ "jpan", // 13 Japanese
+ "geor", // 14 Georgian
+ "khmr", // 15 Khmer
+ "knda", // 16 Kannada
+ "kore", // 17 Korean
+ "laoo", // 18 Lao
+ "mlym", // 19 Malayalam
+ "mymr", // 20 Burmese
+ "orya", // 21 Oriya
+ "guru", // 22 Punjabi
+ "sinh", // 23 Sinhalese
+ "taml", // 24 Tamil
+ "telu", // 25 Telugu
+ "thai", // 26 Thai
+ "nkoo", // 27 N'Ko
+ "blis", // 28 Bliss
+ "hans", // 29 Simplified Chinese
+ "hant", // 30 Traditional Chinese
+ "mong", // 31 Mongolian
+ "syrc" // 32 Syriac
+ ];
+
+ /**
+ * @private
+ * The inverse of the SCRIPT Array.
+ * Maps a script code (like "jpan" for Japanese)
+ * to its index in the SCRIPT Array.
+ */
+ private static const SCRIPT_BY_ID:Object =
+ {
+ latn: 1,
+ ethi: 2,
+ arab: 3,
+ beng: 4,
+ cyrl: 5,
+ thaa: 6,
+ tibt: 7,
+ grek: 8,
+ gujr: 9,
+ hebr: 10,
+ deva: 11,
+ armn: 12,
+ jpan: 13,
+ geor: 14,
+ khmr: 15,
+ knda: 16,
+ kore: 17,
+ laoo: 18,
+ mlym: 19,
+ mymr: 20,
+ orya: 21,
+ guru: 22,
+ sinh: 23,
+ taml: 24,
+ telu: 25,
+ thai: 26,
+ nkoo: 27,
+ blis: 28,
+ hans: 29,
+ hant: 30,
+ mong: 31,
+ syrc: 32
+ };
+
+ /**
+ * @private
+ * This table maps a language and a script to the most
+ * prominent region where that combination is used.
+ *
+ * Note: "is" must be quoted because it is a reserved word.
+ */
+ private static const DEFAULT_REGION_BY_LANG_AND_SCRIPT:Object =
+ {
+ bg: { 5: "bg" }, // Bulgarian / Cyrillic -> Bulgaria
+ ca: { 1: "es" }, // Catalan / Latin -> Spain
+ zh: { 30: "tw", 29: "cn" }, // Chinese / Traditional Chinese -> Taiwan
+ // Chinese / Simplified Chinese -> China
+ cs: { 1: "cz" }, // Czech / Latin -> Czech Republic
+ da: { 1: "dk" }, // Danish / Latin -> Denmark
+ de: { 1: "de" }, // German / Latin -> Germany
+ el: { 8: "gr" }, // Greek / Greek -> Greece
+ en: { 1: "us" }, // English / Latin -> United States
+ es: { 1: "es" }, // Spanish / Latin -> Spain
+ fi: { 1: "fi" }, // Finnish / Latin -> Finland
+ fr: { 1: "fr" }, // French / Latin -> France
+ he: { 10: "il" }, // Hebrew / Hebrew -> Israel
+ hu: { 1: "hu" }, // Hungarian / Latin -> Hungary
+ "is": { 1: "is" }, // Icelandic / Latin -> Iceland
+ it: { 1: "it" }, // Italian / Latin -> Italy
+ ja: { 13: "jp" }, // Japanese / Japanese -> Japan
+ ko: { 17: "kr" }, // Korean / Korean -> Korea
+ nl: { 1: "nl" }, // Dutch / Latin -> Netherlands
+ nb: { 1: "no" }, // Norwegian Bokmaal / Latin -> Norway
+ pl: { 1: "pl" }, // Polish / Latin -> Poland
+ pt: { 1: "br" }, // Portuguese / Latin -> Brazil
+ ro: { 1: "ro" }, // Romanian / Latin -> Romania
+ ru: { 5: "ru" }, // Russian / Cyrillic -> Russia
+ hr: { 1: "hr" }, // Croatian / Latin -> Croatia
+ sk: { 1: "sk" }, // Slovak / Latin -> Slovakia
+ sq: { 1: "al" }, // Albanian / Latin -> Albania
+ sv: { 1: "se" }, // Swedish / Latin -> Sweden
+ th: { 26: "th" }, // Thai / Thai -> Thailand
+ tr: { 1: "tr" }, // Turkish / Latin -> Turkey
+ ur: { 3: "pk" }, // Urdu / Arabic -> Pakistan
+ id: { 1: "id" }, // Indonesian / Latin -> Indonesia
+ uk: { 5: "ua" }, // Ukrainian / Cyrillic -> Ukraine
+ be: { 5: "by" }, // Byelorussian / Cyrillic -> Belarus
+ sl: { 1: "si" }, // Slovenian / Latin -> Slovenia
+ et: { 1: "ee" }, // Estonian / Latin -> Estonia
+ lv: { 1: "lv" }, // Latvian / Latin -> Latvia
+ lt: { 1: "lt" }, // Lithuanian / Latin -> Lithuania
+ fa: { 3: "ir" }, // Persian / Arabic -> Iran
+ vi: { 1: "vn" }, // Vietnamese / Latin -> Vietnam
+ hy: { 12: "am"}, // Armenian / Armenian -> Armenia
+ az: { 1: "az", 5: "az" }, // Azerbaijani / Latin -> Azerbaijan
+ // Azerbaijani / Cyrillic -> Azerbaijan
+ eu: { 1: "es" }, // Basque / Latin -> Spain
+ mk: { 5: "mk" }, // Macedonian / Cyrillic -> Macedonia
+ af: { 1: "za" }, // Afrikaans / Latin -> South Africa
+ ka: { 14: "ge" }, // Georgian / Georgian -> Georgia
+ fo: { 1: "fo" }, // Faeroese / Latin -> Faroe Islands
+ hi: { 11: "in" }, // Hindi / Devanagari -> India
+ ms: { 1: "my" }, // Malay / Latin -> Malaysia
+ kk: { 5: "kz" }, // Kazakh / Cyrillic -> Kazakhstan
+ ky: { 5: "kg" }, // Kirghiz / Cyrillic -> Kyrgyzstan
+ sw: { 1: "ke" }, // Swahili / Latin -> Kenya
+ uz: { 1: "uz", 5: "uz" }, // Uzbek / Latin -> Uzbekistan
+ // Uzbek / Cyrillic -> Uzbekistan
+ tt: { 5: "ru" }, // Tatar / Cyrillic -> Russia
+ pa: { 22: "in" }, // Punjabi / Punjabi -> India
+ gu: { 9: "in" }, // Gujarati / Gujarati -> India
+ ta: { 24: "in" }, // Tamil / Tamil -> India
+ te: { 25: "in" }, // Telugu / Telugu -> India
+ kn: { 16: "in" }, // Kannada / Kannada -> India
+ mr: { 11: "in" }, // Marathi / Devanagari -> India
+ sa: { 11: "in" }, // Sanskrit / Devanagari -> India
+ mn: { 5: "mn" }, // Mongolian / Cyrillic -> Mongolia
+ gl: { 1: "es" }, // Galician / Latin -> Spain
+ kok: { 11: "in" }, // Konkani / Devanagari -> India
+ syr: { 32: "sy" }, // Syriac / Syriac -> Syria
+ dv: { 6: "mv" }, // Dhivehi / Thaana -> Maldives
+ nn: { 1: "no" }, // Norwegian Nynorsk / Latin -> Norway
+ sr: { 1: "cs", 5: "cs" }, // Serbian / Latin -> Serbia
+ // Serbian / Cyrillic -> Serbia
+ cy: { 1: "gb" }, // Welsh / Latin -> United Kingdom
+ mi: { 1: "nz" }, // Maori / Latin -> New Zealand
+ mt: { 1: "mt" }, // Maltese / Latin -> Malta
+ quz: { 1: "bo" }, // Quechua / Latin -> Bolivia
+ tn: { 1: "za" }, // Tswana / Latin -> South Africa
+ xh: { 1: "za" }, // Xhosa / Latin -> South Africa
+ zu: { 1: "za" }, // Zulu / Latin -> South Africa
+ nso: { 1: "za" }, // Northern Sotho / Latin -> South Africa
+ se: { 1: "no" }, // Northern Saami / Latin -> Norway
+ smj: { 1: "no" }, // Lule Saami / Latin -> Norway
+ sma: { 1: "no" }, // Southern Saami / Latin -> Norway
+ sms: { 1: "fi" }, // Skolt Saami / Latin -> Finland
+ smn: { 1: "fi" }, // Inari Saami / Latin -> Finland
+ bs: { 1: "ba" } // Bosnia / Latin -> Bosnia
+ };
+
+ /**
+ * @private
+ * This table maps a language to a script.
+ * It was derived from the entries at
+ * http://www.iana.org/assignments/language-subtag-registry
+ * which have a Suppress-Script property.
+ *
+ * Note: "as", "in", and "is" must be quoted
+ * because they are reserved words.
+ */
+ private static const SCRIPT_ID_BY_LANG:Object =
+ {
+ ab: 5, // Abkhazian -> Cyrillic
+ af: 1, // Afrikaans -> Latin
+ am: 2, // Amharic -> Ethiopian
+ ar: 3, // Arabic -> Arabic
+ "as": 4, // Assamese -> Bengali
+ ay: 1, // Aymara -> Latin
+ be: 5, // Belarusian -> Cyrillic
+ bg: 5, // Bulgarian -> Cyrillic
+ bn: 4, // Bengali -> Bengali
+ bs: 1, // Bosnian -> Latin
+ ca: 1, // Catalan / Valencian -> Latin
+ ch: 1, // Chamorro -> Latin
+ cs: 1, // Czech -> Latin
+ cy: 1, // Welsh -> Latin
+ da: 1, // Danish -> Latin
+ de: 1, // German -> Latin
+ dv: 6, // Dhivehi / Maldivian -> Thaana
+ dz: 7, // Dzongkha -> Tibetan
+ el: 8, // Modern Greek -> Greek
+ en: 1, // English -> Latin
+ eo: 1, // Esperanto -> Latin
+ es: 1, // Spanish / Castilian -> Latin
+ et: 1, // Estonian -> Latin
+ eu: 1, // Basque -> Latin
+ fa: 3, // Persian -> Arabic
+ fi: 1, // Finnish -> Latin
+ fj: 1, // Fijian -> Latin
+ fo: 1, // Faroese -> Latin
+ fr: 1, // French -> Latin
+ frr: 1, // Northern Frisian -> Latin
+ fy: 1, // Western Frisian -> Latin
+ ga: 1, // Irish -> Latin
+ gl: 1, // Galician -> Latin
+ gn: 1, // Guarani -> Latin
+ gu: 9, // Gujarati -> Gujarati
+ gv: 1, // Manx -> Latin
+ he: 10, // Hebrew -> Hebrew
+ hi: 11, // Hindi -> Devanagari
+ hr: 1, // Croatian -> Latin
+ ht: 1, // Haitian Creole -> Latin
+ hu: 1, // Hungarian -> Latin
+ hy: 12, // Armenian -> Armenian
+ id: 1, // Indonesian -> Latin
+ "in": 1, // Indonesian -> Latin
+ "is": 1, // Icelandic -> Latin
+ it: 1, // Italian -> Latin
+ iw: 10, // Hebrew -> Hebrew
+ ja: 13, // Japanese -> Japanese
+ ka: 14, // Georgian -> Georgian
+ kk: 5, // Kazakh -> Cyrillic
+ kl: 1, // Kalaallisut / Greenlandic -> Latin
+ km: 15, // Central Khmer -> Khmer
+ kn: 16, // Kannada -> Kannada
+ ko: 17, // Korean -> Korean
+ la: 1, // Latin -> Latin
+ lb: 1, // Luxembourgish -> Latin
+ ln: 1, // Lingala -> Latin
+ lo: 18, // Lao -> Lao
+ lt: 1, // Lithuanian -> Latin
+ lv: 1, // Latvian -> Latin
+ mg: 1, // Malagasy -> Latin
+ mh: 1, // Marshallese -> Latin
+ mk: 5, // Macedonian -> Cyrillic
+ ml: 19, // Malayalam -> Malayalam
+ mo: 1, // Moldavian -> Latin
+ mr: 11, // Marathi -> Devanagari
+ ms: 1, // Malay -> Latin
+ mt: 1, // Maltese -> Latin
+ my: 20, // Burmese -> Burmese
+ na: 1, // Nauru -> Latin
+ nb: 1, // Norwegian Bokmaal -> Latin
+ nd: 1, // North Ndebele -> Latin
+ ne: 11, // Nepali -> Devanagari
+ nl: 1, // Dutch / Flemish -> Latin
+ nn: 1, // Norwegian Nynorsk -> Latin
+ no: 1, // Norwegian -> Latin
+ nr: 1, // South Ndebele -> Latin
+ ny: 1, // Chichewa / Chewa / Nyanja -> Latin
+ om: 1, // Oromo -> Latin
+ or: 21, // Oriya -> Oriya
+ pa: 22, // Punjabi -> Punjabi
+ pl: 1, // Polish -> Latin
+ ps: 3, // Pashto -> Arabic
+ pt: 1, // Portuguese -> Latin
+ qu: 1, // Quechua -> Latin
+ rn: 1, // Rundi -> Latin
+ ro: 1, // Romanian -> Latin
+ ru: 5, // Russian -> Cyrillic
+ rw: 1, // Kinyarwanda -> Latin
+ sg: 1, // Sango -> Latin
+ si: 23, // Sinhalese -> Sinhalese
+ sk: 1, // Slovak -> Latin
+ sl: 1, // Slovenian -> Latin
+ sm: 1, // Samoan -> Latin
+ so: 1, // Somali -> Latin
+ sq: 1, // Albanian -> Latin
+ ss: 1, // Swati -> Latin
+ st: 1, // Southern Sotho -> Latin
+ sv: 1, // Swedish -> Latin
+ sw: 1, // Swahili -> Latin
+ ta: 24, // Tamil -> Tamil
+ te: 25, // Telugu -> Telugu
+ th: 26, // Thai -> Thai
+ ti: 2, // Tigrinya -> Ethiopian
+ tl: 1, // Tagalog -> Latin
+ tn: 1, // Tswana -> Latin
+ to: 1, // Tonga -> Latin
+ tr: 1, // Turkish -> Latin
+ ts: 1, // Tsonga -> Latin
+ uk: 5, // Ukrainian -> Cyrillic
+ ur: 3, // Urdu -> Arabic
+ ve: 1, // Venda -> Latin
+ vi: 1, // Vietnamese -> Latin
+ wo: 1, // Wolof -> Latin
+ xh: 1, // Xhosa -> Latin
+ yi: 10, // Yiddish -> Hebrew
+ zu: 1, // Zulu -> Latin
+ cpe: 1, // Creoles and pidgins -> Latin
+ dsb: 1, // Lower Sorbian -> Latin
+ frs: 1, // Eastern Frisian -> Latin
+ gsw: 1, // Swiss German / Alemaanic / Alsatian -> Latin
+ hsb: 1, // Upper Sorbian -> Latin
+ kok: 11, // Konkana -> Devanagari
+ mai: 11, // Maithili -> Devanagari
+ men: 1, // Mende -> Latin
+ nds: 1, // Low German -> Latin
+ niu: 1, // Niuean -> Latin
+ nqo: 27, // N'Ko -> N'Ko
+ nso: 1, // Northern Sotho / Pedi / Sepedi -> Latin
+ son: 1, // Songhai -> Latin
+ tem: 1, // Timne -> Latin
+ tkl: 1, // Tokelau -> Latin
+ tmh: 1, // Tamashek -> Latin
+ tpi: 1, // Tok Pisin -> Latin
+ tvl: 1, // Tuvalu -> Latin
+ zbl: 28 // Bliss -> Bliss
+ };
+
+ /**
+ * @private
+ * This table maps a language-as-spoken-in-a-region
+ * to the script used to write it.
+ *
+ * Chinese in China -> Simplified Chinese
+ * Chinese in Singapore -> Simplified Chinese
+ * Chinese in Taiwan -> Traditional Chinese
+ * Chinese in Hong Kong -> Traditional Chinese
+ * Chinese in Macao -> Traditional Chinese
+ * Mongolian in China -> Mongolian
+ * Mongolian in Singapore -> Cyrillic
+ * Punjabi in Pakistan -> Arabic
+ * Punjabi in India -> Punjabi
+ * Hausa in Ghana -> Latin
+ * Hausa in Niger -> Latin
+ */
+ private static const SCRIPT_ID_BY_LANG_AND_REGION:Object =
+ {
+ zh: { cn: 29, sg: 29, tw: 30, hk: 30, mo: 30 },
+ mn: { cn: 31, sg: 5 },
+ pa: { pk: 3, "in": 22 }, // "in" is reserved word
+ ha: { gh: 1, ne: 1 }
+ };
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Given a language and a region, returns the script system
+ * used to write the language there.
+ *
+ * Examples:
+ * lang zh (Chinese), region cn (China) -> hans (Simplified Chinese)
+ * lang zh (Chinese), region tw (Taiwan) -> hast (Traditional Chinese)
+ */
+ public static function getScriptByLangAndRegion(
+ lang:String, region:String):String
+ {
+ var langRegions:Object = SCRIPT_ID_BY_LANG_AND_REGION[lang];
+ if (langRegions == null)
+ return "";
+
+ var scriptID:Object = langRegions[region];
+ if (scriptID == null)
+ return "";
+
+ return SCRIPTS[int(scriptID)].toLowerCase();
+ }
+
+ /**
+ * @private
+ * Given a language, returns the script generally used to write it.
+ *
+ * Examples:
+ * lang bg (Bulgarian) -> cyrl (Cyrillic)
+ */
+ public static function getScriptByLang(lang:String):String
+ {
+ var scriptID:Object = SCRIPT_ID_BY_LANG[lang];
+ if (scriptID == null)
+ return "";
+
+ return SCRIPTS[int(scriptID)].toLowerCase();
+ }
+
+ /**
+ * @private
+ * Given a language and a script used for writing it,
+ * returns the most prominent region where that combination is used.
+ *
+ * Examples:
+ */
+ public static function getDefaultRegionForLangAndScript(
+ lang:String, script:String):String
+ {
+ var langObj:Object = DEFAULT_REGION_BY_LANG_AND_SCRIPT[lang];
+ var scriptID:Object = SCRIPT_BY_ID[script];
+ if (langObj == null || scriptID == null)
+ return "";
+
+ return langObj[int(scriptID)] || "";
+ }
+}
diff --git a/src/mx/resources/ResourceBundle.as b/src/mx/resources/ResourceBundle.as
new file mode 100644
index 00000000..88c5f690
--- /dev/null
+++ b/src/mx/resources/ResourceBundle.as
@@ -0,0 +1,241 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.resources
+{
+
+import flash.system.ApplicationDomain;
+
+import mx.core.mx_internal;
+import mx.utils.StringUtil;
+
+use namespace mx_internal;
+
+/**
+ * Provides an implementation of the IResourceBundle interface.
+ * The IResourceManager and IResourceBundle interfaces work together
+ * to provide internationalization support for Flex applications.
+ *
+ * A Flex application typically has multiple instances of this class, + * all managed by a single instance of the ResourceManager class. + * It is possible to have ResourceBundle instances for multiple locales, + * one for each locale. There can be multiple ResourceBundle instances with + * different bundle names.
+ * + * @see mx.resources.IResourceBundle + * @see mx.resources.IResourceManager + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class ResourceBundle implements IResourceBundle +{ + include "../core/Version.as"; + + //-------------------------------------------------------------------------- + // + // Class variables + // + //-------------------------------------------------------------------------- + + /** + * @private + * Set by SystemManager constructor in order to make the deprecated + * getResourceBundle() method work with the new resource scheme + * in the single-locale case. + */ + mx_internal static var locale:String; + + /** + * @private + * Set by bootstrap loaders + * to allow for alternate search paths for resources + */ + mx_internal static var backupApplicationDomain:ApplicationDomain; + + //-------------------------------------------------------------------------- + // + // Class methods + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + private static function getClassByName(name:String, + domain:ApplicationDomain):Class + { + var c:Class; + + if (domain.hasDefinition(name)) + c = domain.getDefinition(name) as Class; + + return c; + } + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @param locale A locale string, such as"en_US".
+ *
+ * @param bundleName A name that identifies this bundle,
+ * such as "MyResources".
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function ResourceBundle(locale:String = null,
+ bundleName:String = null)
+ {
+ // The only reason that the arguments are optional is so that
+ // Flex 3 applications can link against Flex 2 resource SWCs.
+ // In Flex 2, the constructor had no arguments at all
+ // and the autogenerated ResourceBundle subclasses
+ // therefore called super() with no arguments.
+ // If, in Flex 3, the constructor has required arguments,
+ // this causes a VerifyError.
+
+ super();
+
+ _locale = locale;
+ _bundleName = bundleName;
+
+ _content = getContent();
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // bundleName
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the bundleName property.
+ */
+ mx_internal var _bundleName:String;
+
+ /**
+ * @copy mx.resources.IResourceBundle#bundleName
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get bundleName():String
+ {
+ return _bundleName;
+ }
+
+ //----------------------------------
+ // content
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the content property.
+ */
+ private var _content:Object = {};
+
+ /**
+ * @copy mx.resources.IResourceBundle#content
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get content():Object
+ {
+ return _content;
+ }
+
+ //----------------------------------
+ // locale
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the locale property.
+ */
+ mx_internal var _locale:String;
+
+ /**
+ * @copy mx.resources.IResourceBundle#locale
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get locale():String
+ {
+ return _locale;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * When a properties file is compiled into a resource bundle,
+ * the MXML compiler autogenerates a subclass of ResourceBundle.
+ * The subclass overrides this method to return an Object
+ * that contains key-value pairs for the bundle's resources.
+ *
+ * If you create your own ResourceBundle instances,
+ * you can set the key-value pairs on the content object.
A single instance of an IResourceManager implementation + * manages all localized resources + * for a Flex application.
+ * + * @see mx.resources.IResourceManager + * @see mx.resources.IResourceBundle + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class ResourceManager +{ + include "../core/Version.as"; + + //-------------------------------------------------------------------------- + // + // Class variables + // + //-------------------------------------------------------------------------- + + /** + * @private + * Linker dependency on implementation class. + */ + private static var implClassDependency:ResourceManagerImpl; + + /** + * @private + * The sole instance of the ResourceManager. + */ + private static var instance:IResourceManager; + + //-------------------------------------------------------------------------- + // + // Class methods + // + //-------------------------------------------------------------------------- + + /** + * Gets the single instance of the ResourceManager class. + * This object manages all localized resources for a Flex application. + * + * @return An object implementing IResourceManager. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public static function getInstance():IResourceManager + { + if (!instance) + { + /* + CONFIG::performanceInstrumentation + { + var perfUtil:mx.utils.PerfUtil = mx.utils.PerfUtil.getInstance(); + perfUtil.markTime("ResourceManager.getInstance().start"); + } + */ + if (!Singleton.getClass("mx.resources::IResourceManager")) + // install ResourceManagerImpl if not registered already + Singleton.registerClass("mx.resources::IResourceManager", + Class(getDefinitionByName("mx.resources::ResourceManagerImpl"))); + + + try + { + instance = IResourceManager( + Singleton.getInstance("mx.resources::IResourceManager")); + } + catch(e:Error) + { + // In non-Flex apps and modules, the Singleton manager + // won't have been initialized by SystemManager + // or FlexModuleFactory (since these don't get linked in) + // so the above call to getInstance() will throw an exception. + // In this situation, the ResourceManager simply creates + // its own ResourceManagerImpl. + instance = new ResourceManagerImpl(); + } +/* + CONFIG::performanceInstrumentation + { + perfUtil.markTime("ResourceManager.getInstance().end"); + } +*/ + } + + return instance; + } + +} + +} \ No newline at end of file diff --git a/src/mx/resources/ResourceManagerImpl.as b/src/mx/resources/ResourceManagerImpl.as new file mode 100644 index 00000000..366d0c6a --- /dev/null +++ b/src/mx/resources/ResourceManagerImpl.as @@ -0,0 +1,1314 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2007 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.resources +{ + +import flash.events.Event; +import flash.events.EventDispatcher; +import flash.events.FocusEvent; +import flash.events.IEventDispatcher; +import flash.events.TimerEvent; +import flash.system.ApplicationDomain; +import flash.system.Capabilities; +import flash.system.SecurityDomain; +import flash.utils.Dictionary; +import flash.utils.Timer; +import mx.core.IFlexModuleFactory; +import mx.core.mx_internal; +import mx.core.Singleton; +import mx.events.FlexEvent; +import mx.events.ModuleEvent; +import mx.events.ResourceEvent; +//import mx.managers.SystemManagerGlobals; +import mx.modules.IModuleInfo; +//import mx.modules.ModuleManager; +import mx.utils.StringUtil; + +use namespace mx_internal; + +/** + * @copy mx.resources.IResourceManager#change + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +[Event(name="change", type="flash.events.Event")] + +[ExcludeClass] + +/** + * @private + * This class provides an implementation of the IResourceManager interface. + * The IResourceManager and IResourceBundle interfaces work together + * to provide internationalization support for Flex applications. + * + *A single instance of this class manages all localized resources + * for a Flex application.
+ * + * @see mx.resources.IResourceManager + * @see mx.resources.IResourceBundle + */ +public class ResourceManagerImpl extends EventDispatcher implements IResourceManager +{ + include "../core/Version.as"; + + //-------------------------------------------------------------------------- + // + // Class variables + // + //-------------------------------------------------------------------------- + + /** + * @private + * The sole instance of the ResourceManager. + */ + private static var instance:IResourceManager; + + //-------------------------------------------------------------------------- + // + // Class methods + // + //-------------------------------------------------------------------------- + + /** + * Gets the single instance of the ResourceManagerImpl class. + * This object manages all localized resources for a Flex application. + * + * @return An object implementing IResourceManager. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public static function getInstance():IResourceManager + { + if (!instance) + instance = new ResourceManagerImpl(); + + return instance; + } + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function ResourceManagerImpl() + { + super(); +/* + if (SystemManagerGlobals.topLevelSystemManagers.length) + { + if (SystemManagerGlobals.topLevelSystemManagers[0].currentFrame == 1) + { + ignoreMissingBundles = true; + SystemManagerGlobals.topLevelSystemManagers[0]. + addEventListener(Event.ENTER_FRAME, enterFrameHandler); + } + } + + var info:Object = SystemManagerGlobals.info; + if (info) + processInfo(info, false); + + ignoreMissingBundles = false; + + if (SystemManagerGlobals.topLevelSystemManagers.length) + SystemManagerGlobals.topLevelSystemManagers[0]. + addEventListener(FlexEvent.NEW_CHILD_APPLICATION, newChildApplicationHandler); + */ + } + + //-------------------------------------------------------------------------- + // + // Variables + // + //-------------------------------------------------------------------------- + + /** + * @private + * + * Whether or not to throw an error. + */ + private var ignoreMissingBundles:Boolean; + + /** + * @private + * + * The dictionary to hold all of the weak reference resource bundles. + */ + private var bundleDictionary:Dictionary; + + /** + * @private + * A map whose keys are locale strings like "en_US" + * and whose values are "bundle maps". + * A bundle map is a map whose keys are bundle names + * like "SharedResources" and whose values are ResourceBundle instances. + * You can get to an individual resource value like this: + * localeMap["en_US"]["SharedResources"].content["currencySymbol"] + */ + private var localeMap:Object = {}; + + /** + * @private + * A map whose keys are URLs for resource modules that have been loaded + * and whose values are ResourceModuleInfo instances for those modules. + */ + private var resourceModules:Object = {}; + + /** + * @private + */ + private var initializedForNonFrameworkApp:Boolean = false; + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // localeChain + //---------------------------------- + + /** + * @private + * Storage for the localeChain property. + */ + private var _localeChain:Array /* of String */; + + /** + * @copy mx.resources.IResourceManager#localeChain + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get localeChain():Array /* of String */ + { + return _localeChain; + } + + /** + * @private + */ + public function set localeChain(value:Array /* of String */):void + { + _localeChain = value; + + update(); + } + + //-------------------------------------------------------------------------- + // + // Methods + // + //-------------------------------------------------------------------------- + + /** + * @private + * This method is called by the SystemManager class of an Application + * when the application starts. + * It is also called by the FlexModuleFactory class of a code module + * when that module gets loaded. + * + * The MXML compiler autogenerated code which set the + * "compiledLocales" and "compiledResourceBundleNames" properties + * of the info() Object required by the IFlexModuleFactory + * interface that these classes implement. + * These two properties together indicate which resource bundle + * classes the MXML compiler autogenerated and linked into the + * application or module. + * + * The "compiledLocales" property has been set to the locales + * which were specified at compile time using the -locale option. + * For example, if you compile with -locale=en_US,ja_JP + * then the "compiledLocales" property is the array [ "en_US", "ja_JP" ]. + * + * The "compiledResourceBundleNames" property has been set + * to the names of the resource bundles which are used by + * the application or module, as determined by the compiler + * from [ResourceBundle] metadata and ~~Resource() directives. + * For example, if the classes in the application or module + * declare that they use resource bundles named "core" and "MyApp", + * then the "compiledResourceBundleNames" property is the array + * [ "core", "MyApp" ]. + * + * The compiler autogenerated a ResourceBundle subclass for each + * (locale, bundle name) pair. + * For example, with the above locales and bundle names, + * there would be four classes: + * en_US$core_properties + * en_US$MyApp_properties + * ja_JP$core_properties + * ja_JP$MyApp_properties + * + * This method creates one instance of each such class + * and installs it into the ResourceManager with addResourceBundle(). + * If a bundle for a given locale and bundle name already exists + * in the ResourceManager already exists, it does not get replaced. + * This can happen when a code module gets loaded into an application. + * + * When sub-applications and modules install their resource bundles + * they set useWeakReference = true. Any new resource bundles they + * create will be weak referenced by the ResourceManager. The + * sub-application or module will then provide a hard reference + * to the returned Array of resource bundles to keep them from + * being garbage collected. + */ + public function installCompiledResourceBundles( + applicationDomain:ApplicationDomain, + locales:Array /* of String */, + bundleNames:Array /* of String */, + useWeakReference:Boolean = false):Array + { + //trace("locales", locales); + //trace("bundleNames", bundleNames); + var bundles:Array = []; + var bundleCount:uint = 0; + var n:int = locales ? locales.length : 0; + var m:int = bundleNames ? bundleNames.length : 0; + + // Loop over the locales. + for (var i:int = 0; i < n; i++) + { + var locale:String = locales[i]; + + // Loop over the bundle names. + for (var j:int = 0; j < m; j++) + { + var bundleName:String = bundleNames[j]; + + var bundle:IResourceBundle = installCompiledResourceBundle( + applicationDomain, locale, bundleName, + useWeakReference); + + if (bundle) + bundles[bundleCount++] = bundle; + } + } + + return bundles; + } + + /** + * @private + */ + private function installCompiledResourceBundle( + applicationDomain:ApplicationDomain, + locale:String, bundleName:String, + useWeakReference:Boolean = false):IResourceBundle + { + var packageName:String = null; + var localName:String = bundleName; + var colonIndex:int = bundleName.indexOf(":"); + if (colonIndex != -1) + { + packageName = bundleName.substring(0, colonIndex); + localName = bundleName.substring(colonIndex + 1); + } + + // If a bundle with that locale and bundle name already exists + // in the ResourceManager, don't replace it. + // If we want to install a weakReferenceDictionary then don't rely on + // a weak reference dictionary because it may go way when the + // application goes away. + var resourceBundle:IResourceBundle = getResourceBundleInternal(locale, + bundleName, + useWeakReference); + if (resourceBundle) + return resourceBundle; + + // The autogenerated resource bundle classes produced by the + // mxmlc and compc compilers have names that incorporate + // the locale and bundle name, such as "en_US$core_properties". + var resourceBundleClassName:String = + locale + "$" + localName + "_properties"; + if (packageName != null) + resourceBundleClassName = packageName + "." + resourceBundleClassName; + + // Find the bundle class by its name. + // We do a hasDefinition() check before calling getDefinition() + // because getDefinition() will throw an RTE + // if the class doesn't exist. + var bundleClass:Class = null; + if (applicationDomain.hasDefinition(resourceBundleClassName)) + { + bundleClass = Class(applicationDomain.getDefinition( + resourceBundleClassName)); + } + + if (!bundleClass) + { + resourceBundleClassName = bundleName; + if (applicationDomain.hasDefinition(resourceBundleClassName)) + { + bundleClass = Class(applicationDomain.getDefinition( + resourceBundleClassName)); + } + } + + // In case we linked against a Flex 2 SWC, look for the old + // class name. + if (!bundleClass) + { + resourceBundleClassName = bundleName + "_properties"; + if (applicationDomain.hasDefinition(resourceBundleClassName)) + { + bundleClass = Class(applicationDomain.getDefinition( + resourceBundleClassName)); + } + } + + if (!bundleClass) + { + if (ignoreMissingBundles) + return null; + + throw new Error( + "Could not find compiled resource bundle '" + bundleName + + "' for locale '" + locale + "'."); + } + + // Create an instance of the bundle class. + resourceBundle = ResourceBundle(new bundleClass()); + + // In case we just created a ResourceBundle from a Flex 2 SWC, + // set its locale and bundleName, because the old constructor + // didn't used to do this. + ResourceBundle(resourceBundle)._locale = locale; + ResourceBundle(resourceBundle)._bundleName = bundleName; + + // Add that resource bundle instance to the ResourceManager. + addResourceBundle(resourceBundle, useWeakReference); + + return resourceBundle; + } + + // FocusEvent is used just so we can add a relatedObject + private function newChildApplicationHandler(event:FocusEvent):void + { + var info:Object = event.relatedObject["info"](); + var weakReference:Boolean = false; + if ("_resourceBundles" in event.relatedObject) + weakReference = true; + + // If the application has a "_resourceBundles" object for us to put + // the bundles into then we will. Otherwise have the ResourceManager + // create a hard reference to the resources. + var bundles:Array = processInfo(info, weakReference); + if (weakReference) + event.relatedObject["_resourceBundles"] = bundles; + } + + private function processInfo(info:Object, useWeakReference:Boolean):Array + { + var compiledLocales:Array = info["compiledLocales"]; + + ResourceBundle.locale = + compiledLocales != null && compiledLocales.length > 0 ? + compiledLocales[0] : + "en_US"; +/* + // The FlashVars of the SWF's HTML wrapper, + // or the query parameters of the SWF URL, + // can specify the ResourceManager's localeChain. + var localeChainList:String = + SystemManagerGlobals.parameters["localeChain"]; + if (localeChainList != null && localeChainList != "") + localeChain = localeChainList.split(","); + + var applicationDomain:ApplicationDomain = info["currentDomain"]; + + var compiledResourceBundleNames:Array = + info["compiledResourceBundleNames"]; + + var bundles:Array = installCompiledResourceBundles( + applicationDomain, compiledLocales, compiledResourceBundleNames, + useWeakReference); + + // If the localeChain wasn't specified in the FlashVars of the SWF's + // HTML wrapper, or in the query parameters of the SWF URL, + // then initialize it to the list of compiled locales, + // sorted according to the system's preferred locales as reported by + // Capabilities.languages or Capabilities.language. + // For example, if the applications was compiled with, say, + // -locale=en_US,ja_JP and Capabilities.languages reports [ "ja-JP" ], + // set the localeChain to [ "ja_JP" "en_US" ]. + if (!localeChain) + initializeLocaleChain(compiledLocales); +*/ + return [];//bundles; + } + + /** + * @copy mx.resources.IResourceManager#initializeLocaleChain() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function initializeLocaleChain(compiledLocales:Array):void + { + localeChain = LocaleSorter.sortLocalesByPreference( + compiledLocales, getSystemPreferredLocales(), null, true); + } + + /** + * @copy mx.resources.IResourceManager#loadResourceModule() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function loadResourceModule(url:String, updateFlag:Boolean = true, + applicationDomain:ApplicationDomain = null, + securityDomain:SecurityDomain = null): + IEventDispatcher + { + /* + var moduleInfo:IModuleInfo = ModuleManager.getModule(url); + + // Create the per-load IEventDispatcher that we'll return. + var resourceEventDispatcher:ResourceEventDispatcher = + new ResourceEventDispatcher(moduleInfo); + + // Set up a handler for the "ready" event from the module. + // We use a local Function rather than a method + // so that it can access the 'update' argument. + var readyHandler:Function = function(event:ModuleEvent):void + { + //trace("readyHandler"); + + var resourceModule:* = // IResourceModule + event.module.factory.create(); + + //dumpResourceModule(resourceModule); + + resourceModules[event.module.url].resourceModule = resourceModule; + + if (updateFlag) + update(); + } + moduleInfo.addEventListener(ModuleEvent.READY, readyHandler, + false, 0, true); + + // Set up a handler for the "error" event from the module. + // We use a local Function rather than a method + // for symmetry with the readyHandler. + var errorHandler:Function = function(event:ModuleEvent):void + { + var message:String = "Unable to load resource module from " + url; + + if (resourceEventDispatcher.willTrigger(ResourceEvent.ERROR)) + { + var resourceEvent:ResourceEvent = new ResourceEvent( + ResourceEvent.ERROR, event.bubbles, event.cancelable); + resourceEvent.bytesLoaded = 0; + resourceEvent.bytesTotal = 0; + resourceEvent.errorText = message; + resourceEventDispatcher.dispatchEvent(resourceEvent); + } + else + { + throw new Error(message); + } + } + moduleInfo.addEventListener(ModuleEvent.ERROR, errorHandler, + false, 0, true); + + resourceModules[url] = + new ResourceModuleInfo(moduleInfo, readyHandler, errorHandler); + + // This Timer gives the loadResourceModules() caller a chance + // to add event listeners to the return value, before the module + // is loaded. + // We use a local Function for the timerHandler rather than a method + // so that it can access the 'moduleInfo' local var. + var timer:Timer = new Timer(0); + var timerHandler:Function = function(event:TimerEvent):void + { + timer.removeEventListener(TimerEvent.TIMER, timerHandler); + timer.stop(); + + //trace("loading"); + + // Start loading the module. + moduleInfo.load(applicationDomain, securityDomain); + } + timer.addEventListener(TimerEvent.TIMER, timerHandler, + false, 0, true); + timer.start(); + */ + return null;//resourceEventDispatcher; + } + + /** + * @copy mx.resources.IResourceManager#unloadResourceModule() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function unloadResourceModule(url:String, update:Boolean = true):void + { + // Get the resource module info. + var rmi:ResourceModuleInfo = resourceModules[url]; + if (!rmi) + return; + + if (rmi.resourceModule) + { + // Get the bundles in this module. + var bundles:Array = rmi.resourceModule.resourceBundles; + if (bundles) + { + var n:int = bundles.length; + for (var i:int = 0; i < n; i++) + { + // Remove each bundle. + var locale:String = bundles[i].locale; + var bundleName:String = bundles[i].bundleName; + removeResourceBundle(locale, bundleName); + } + } + } + + // Remove all links to the module. + resourceModules[url] = null; + delete resourceModules[url]; + + // Unload the module. + rmi.moduleInfo.unload(); + + // Update if necessary. + if (update) + this.update(); + } + + /** + * @copy mx.resources.IResourceManager#addResourceBundle() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function addResourceBundle(resourceBundle:IResourceBundle, + useWeakReference:Boolean = false):void + { + var locale:String = resourceBundle.locale; + var bundleName:String = resourceBundle.bundleName; + + if (!localeMap[locale]) + localeMap[locale] = {}; + + if (useWeakReference) + { + if (!bundleDictionary) + { + bundleDictionary = new Dictionary(true); + } + + bundleDictionary[resourceBundle] = locale + bundleName; + localeMap[locale][bundleName] = bundleDictionary; + } + else + { + localeMap[locale][bundleName] = resourceBundle; + } + } + + /** + * @copy mx.resources.IResourceManager#getResourceBundle() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function getResourceBundle(locale:String, + bundleName:String):IResourceBundle + { + return getResourceBundleInternal(locale, bundleName, false); + } + + /** + * @private + * + * @param ignoreWeakReferenceBundles if true, do not search weak + * reference bundles. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + private function getResourceBundleInternal(locale:String, + bundleName:String, + ignoreWeakReferenceBundles:Boolean):IResourceBundle + { + var bundleMap:Object = localeMap[locale]; + if (!bundleMap) + return null; + + var bundle:IResourceBundle = null; + var bundleObject:Object = bundleMap[bundleName]; + if (bundleObject is Dictionary) + { + if (ignoreWeakReferenceBundles) + return null; + + var localeBundleNameString:String = locale + bundleName; + for (var obj:Object in bundleObject) + { + if (bundleObject[obj] == localeBundleNameString) + { + bundle = obj as IResourceBundle; + break; + } + } + } + else + { + bundle = bundleObject as IResourceBundle; + } + + return bundle; + } + + /** + * @copy mx.resources.IResourceManager#removeResourceBundle() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function removeResourceBundle(locale:String, bundleName:String):void + { + // Remove the specified bundle. + delete localeMap[locale][bundleName]; + + // If that leaves a locale node with no bundles, + // delete the locale node. + if (getBundleNamesForLocale(locale).length == 0) + delete localeMap[locale]; + } + + /** + * @copy mx.resources.IResourceManager#removeResourceBundlesForLocale() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function removeResourceBundlesForLocale(locale:String):void + { + delete localeMap[locale]; + } + + /** + * @copy mx.resources.IResourceManager#update() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function update():void + { + dispatchEvent(new Event(Event.CHANGE)); + } + + /** + * @copy mx.resources.IResourceManager#getLocales() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function getLocales():Array /* of String */ + { + var locales:Array = []; + for (var p:String in localeMap) + { + locales.push(p); + } + return locales; + } + + /** + * @copy mx.resources.IResourceManager#getPreferredLocaleChain() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function getPreferredLocaleChain():Array /* of String */ + { + return LocaleSorter.sortLocalesByPreference( + getLocales(), getSystemPreferredLocales(), null, true); + } + + /** + * @copy mx.resources.IResourceManager#getBundleNamesForLocale() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function getBundleNamesForLocale(locale:String):Array /* of String */ + { + var bundleNames:Array = []; + for (var p:String in localeMap[locale]) + { + bundleNames.push(p); + } + return bundleNames; + } + + /** + * @copy mx.resources.findResourceBundleWithResource + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function findResourceBundleWithResource( + bundleName:String, resourceName:String):IResourceBundle + { + if (!_localeChain) + return null; + + var n:int = _localeChain.length; + for (var i:int = 0; i < n; i++) + { + var locale:String = localeChain[i]; + + var bundleMap:Object = localeMap[locale]; + if (!bundleMap) + continue; + + var bundleObject:Object = bundleMap[bundleName]; + if (!bundleObject) + continue; + + var bundle:IResourceBundle = null; + + if (bundleObject is Dictionary) + { + var localeBundleNameString:String = locale + bundleName; + for (var obj:Object in bundleObject) + { + if (bundleObject[obj] == localeBundleNameString) + { + bundle = obj as IResourceBundle; + break; + } + } + } + else + { + bundle = bundleObject as IResourceBundle; + } + + if (bundle && resourceName in bundle.content) + return bundle; + } + + return null; + } + + [Bindable("change")] + + /** + * @copy mx.resources.IResourceManager#getObject() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function getObject(bundleName:String, resourceName:String, + locale:String = null):* + { + var resourceBundle:IResourceBundle = + findBundle(bundleName, resourceName, locale); + if (!resourceBundle) + return undefined; + + return resourceBundle.content[resourceName]; + } + + [Bindable("change")] + + /** + * @copy mx.resources.IResourceManager#getString() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function getString(bundleName:String, resourceName:String, + parameters:Array = null, + locale:String = null):String + { + var resourceBundle:IResourceBundle = + findBundle(bundleName, resourceName, locale); + if (!resourceBundle) + return null; + + var value:String = String(resourceBundle.content[resourceName]); + + if (parameters) + value = StringUtil.substitute(value, parameters); + + return value; + } + + [Bindable("change")] + + /** + * @copy mx.resources.IResourceManager#getStringArray() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function getStringArray(bundleName:String, + resourceName:String, + locale:String = null):Array /* of String */ + { + var resourceBundle:IResourceBundle = + findBundle(bundleName, resourceName, locale); + if (!resourceBundle) + return null; + + var value:* = resourceBundle.content[resourceName]; + + var array:Array = String(value).split(","); + + var n:int = array.length; + for (var i:int = 0; i < n; i++) + { + array[i] = StringUtil.trim(array[i]); + } + + return array; + } + + [Bindable("change")] + + /** + * @copy mx.resources.IResourceManager#getNumber() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function getNumber(bundleName:String, resourceName:String, + locale:String = null):Number + { + var resourceBundle:IResourceBundle = + findBundle(bundleName, resourceName, locale); + if (!resourceBundle) + return NaN; + + var value:* = resourceBundle.content[resourceName]; + + return Number(value); + } + + [Bindable("change")] + + /** + * @copy mx.resources.IResourceManager#getInt() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function getInt(bundleName:String, resourceName:String, + locale:String = null):int + { + var resourceBundle:IResourceBundle = + findBundle(bundleName, resourceName, locale); + if (!resourceBundle) + return 0; + + var value:* = resourceBundle.content[resourceName]; + + return int(value); + } + + [Bindable("change")] + + /** + * @copy mx.resources.IResourceManager#getUint() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function getUint(bundleName:String, resourceName:String, + locale:String = null):uint + { + var resourceBundle:IResourceBundle = + findBundle(bundleName, resourceName, locale); + if (!resourceBundle) + return 0; + + var value:* = resourceBundle.content[resourceName]; + + return uint(value); + } + + [Bindable("change")] + + /** + * @copy mx.resources.IResourceManager#getBoolean() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function getBoolean(bundleName:String, resourceName:String, + locale:String = null):Boolean + { + var resourceBundle:IResourceBundle = + findBundle(bundleName, resourceName, locale); + if (!resourceBundle) + return false; + + var value:* = resourceBundle.content[resourceName]; + + return String(value).toLowerCase() == "true"; + } + + [Bindable("change")] + + /** + * @copy mx.resources.IResourceManager#getClass() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function getClass(bundleName:String, resourceName:String, + locale:String = null):Class + { + var resourceBundle:IResourceBundle = + findBundle(bundleName, resourceName, locale); + if (!resourceBundle) + return null; + + var value:* = resourceBundle.content[resourceName]; + + return value as Class; + } + + /** + * @private. + */ + private function findBundle(bundleName:String, resourceName:String, + locale:String):IResourceBundle + { + supportNonFrameworkApps(); + + return locale != null ? + getResourceBundle(locale, bundleName) : + findResourceBundleWithResource(bundleName, resourceName); + + } + + /** + * @private. + */ + private function supportNonFrameworkApps():void + { + if (initializedForNonFrameworkApp) + return; + initializedForNonFrameworkApp = true; + + if (getLocales().length > 0) + return; + + var applicationDomain:ApplicationDomain = + ApplicationDomain.currentDomain; + + if (!applicationDomain.hasDefinition("_CompiledResourceBundleInfo")) + return; + var c:Class = Class(applicationDomain.getDefinition( + "_CompiledResourceBundleInfo")); + + var locales:Array /* of String */ = c.compiledLocales; + var bundleNames:Array /* of String */ = c.compiledResourceBundleNames; + + installCompiledResourceBundles( + applicationDomain, locales, bundleNames); + + localeChain = locales; + } + + /** + * @private + */ + private function getSystemPreferredLocales():Array /* of String */ + { + var systemPreferences:Array; + + // Capabilities.languages was added in AIR 1.1, + // so this API may not exist. + if (Capabilities["languages"]) + systemPreferences = Capabilities["languages"]; + else + systemPreferences = [ Capabilities.language ]; + + return systemPreferences; + } + + /** + * @private. + */ + private function dumpResourceModule(resourceModule:*):void + { + for each (var bundle:ResourceBundle in resourceModule.resourceBundles) + { + trace(bundle.locale, bundle.bundleName); + for (var p:String in bundle.content) + { + //trace(p, bundle.getObject(p)); + } + } + } + + /** + * @private + */ + private function enterFrameHandler(event:Event):void + { + /* + if (SystemManagerGlobals.topLevelSystemManagers.length) + { + if (SystemManagerGlobals.topLevelSystemManagers[0].currentFrame == 2) + { + SystemManagerGlobals.topLevelSystemManagers[0]. + removeEventListener(Event.ENTER_FRAME, enterFrameHandler); + } + else + return; + } + + var info:Object = SystemManagerGlobals.info; + if (info) + processInfo(info, false); + */ + } +} + +} + +import flash.events.EventDispatcher; +import mx.events.ModuleEvent; +import mx.events.ResourceEvent; +import mx.modules.IModuleInfo; +import mx.resources.IResourceModule; + +//////////////////////////////////////////////////////////////////////////////// +// +// Helper class: ResourceModuleInfo +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * @private + */ +class ResourceModuleInfo +{ + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function ResourceModuleInfo(moduleInfo:IModuleInfo, + readyHandler:Function, + errorHandler:Function) + { + super(); + + this.moduleInfo = moduleInfo; + this.readyHandler = readyHandler; + this.errorHandler = errorHandler; + } + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // errorHandler + //---------------------------------- + + /** + * @private + */ + public var errorHandler:Function; + + //---------------------------------- + // moduleInfo + //---------------------------------- + + /** + * @private + */ + public var moduleInfo:IModuleInfo + + //---------------------------------- + // readyHandler + //---------------------------------- + + /** + * @private + */ + public var readyHandler:Function; + + //---------------------------------- + // resourceModule + //---------------------------------- + + /** + * @private + */ + public var resourceModule:IResourceModule; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Helper class: ResourceEventDispatcher +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * @private + */ +class ResourceEventDispatcher extends EventDispatcher +{ + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function ResourceEventDispatcher(moduleInfo:IModuleInfo) + { + super(); + + moduleInfo.addEventListener( + ModuleEvent.ERROR, moduleInfo_errorHandler, false, 0, true); + + moduleInfo.addEventListener( + ModuleEvent.PROGRESS, moduleInfo_progressHandler, false, 0, true); + + moduleInfo.addEventListener( + ModuleEvent.READY, moduleInfo_readyHandler, false, 0, true); + } + + //-------------------------------------------------------------------------- + // + // Event handlers + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + private function moduleInfo_errorHandler(event:ModuleEvent):void + { + var resourceEvent:ResourceEvent = new ResourceEvent( + ResourceEvent.ERROR, event.bubbles, event.cancelable); + resourceEvent.bytesLoaded = event.bytesLoaded; + resourceEvent.bytesTotal = event.bytesTotal; + resourceEvent.errorText = event.errorText; + dispatchEvent(resourceEvent); + } + + /** + * @private + */ + private function moduleInfo_progressHandler(event:ModuleEvent):void + { + var resourceEvent:ResourceEvent = new ResourceEvent( + ResourceEvent.PROGRESS, event.bubbles, event.cancelable); + resourceEvent.bytesLoaded = event.bytesLoaded; + resourceEvent.bytesTotal = event.bytesTotal; + dispatchEvent(resourceEvent); + } + + /** + * @private + */ + private function moduleInfo_readyHandler(event:ModuleEvent):void + { + var resourceEvent:ResourceEvent = + new ResourceEvent(ResourceEvent.COMPLETE); + dispatchEvent(resourceEvent); + } +} diff --git a/src/mx/rpc/IResponder.as b/src/mx/rpc/IResponder.as new file mode 100644 index 00000000..88b9fa22 --- /dev/null +++ b/src/mx/rpc/IResponder.as @@ -0,0 +1,52 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2005-2006 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.rpc +{ + +/** + * This interface provides the contract for any service + * that needs to respond to remote or asynchronous calls. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public interface IResponder +{ + /** + * This method is called by a service when the return value + * has been received. + * Whiledata is typed as Object, it is often
+ * (but not always) an mx.rpc.events.ResultEvent.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function result(data:Object):void;
+
+ /**
+ * This method is called by a service when an error has been received.
+ * While info is typed as Object it is often
+ * (but not always) an mx.rpc.events.FaultEvent.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function fault(info:Object):void;
+}
+
+}
diff --git a/src/mx/states/AddItems.as b/src/mx/states/AddItems.as
new file mode 100644
index 00000000..f1a7d67a
--- /dev/null
+++ b/src/mx/states/AddItems.as
@@ -0,0 +1,99 @@
+package mx.states
+{
+ import flash.display.DisplayObject;
+
+ import mx.collections.IList;
+ import mx.core.DeferredInstanceFromFunction;
+
+ public class AddItems extends OverrideBase implements IOverride
+ {
+
+ static public const FIRST:String = "first";
+ static public const BEFORE:String = "before";
+ static public const AFTER:String = "after";
+ static public const LAST:String = "last";
+
+ public var itemsFactory:*;
+ public var destination:*;
+ public var propertyName:String;
+ public var position:String;
+ public var relativeTo:Array = [];
+
+ public var destructionPolicy:String;
+
+ private var item:*; // garbage collection?
+
+ override public function initialize():void {
+ //trace("init");
+ }
+
+ override public function apply(parent:Object):void {
+ var object:* = getOverrideContext(destination, parent);
+ item = (itemsFactory as DeferredInstanceFromFunction).getInstance();
+ if(propertyName == null || propertyName == "mxmlContent") {
+ parent.addElement(item);
+ } else if(object[propertyName] is IList) {
+ applyToList(parent, object, item);
+ } /*else if(object is Array) {
+ applyToArray(object as Array, item);
+ }*/
+ }
+
+ override public function remove(parent:Object):void {
+ var object:* = getOverrideContext(destination, parent);
+ if(propertyName == null || propertyName == "mxmlContent") {
+ parent.removeElement(item);
+ } else if(object[propertyName] is IList) {
+ removeFromList(parent, object, item);
+ }
+ item = null;
+ }
+
+ private function applyToList(parent:Object, object:*, item:*):void {
+ var index:int = getInsertIndex(parent, position, object);
+ (object[propertyName] as IList).addItemAt(item, index);
+ }
+ /*
+ private function applyToArray(array:Array, item:*):void {
+ var index:int = getInsertIndex(position, array.length);
+ array[index] = item;
+ }
+ */
+
+ private function removeFromList(parent:Object, object:*, item:*):void {
+ var index:int = (object[propertyName] as IList).getItemIndex(item);
+ (object[propertyName] as IList).removeItemAt(index);
+ }
+
+ private function getInsertIndex(parent:Object, position:String, dest:*):int {
+ switch(position) {
+ case FIRST: return 0;
+ case LAST: return (dest[propertyName] as IList).length; // last = added to new index
+ case AFTER: return getRelatedIndex(parent, dest)+1;
+ case BEFORE: return getRelatedIndex(parent, dest);
+ }
+ return -1;
+ }
+
+ private function getRelatedIndex(parent:Object, object:Object):int {
+ if(relativeTo is Array) {
+
+ for(var i:int = 0; i < relativeTo.length; i++) {
+ if(parent[relativeTo[i]]) {
+ return getObjectIndex(parent[relativeTo[i]], object);
+ }
+ }
+
+ }
+ return -1;
+ }
+
+ private function getObjectIndex(child:Object, parent:Object):int {
+ if(parent[propertyName] is IList) {
+ return (parent[propertyName] as IList).getItemIndex(child);
+ }
+ return -1;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/mx/states/IOverride.as b/src/mx/states/IOverride.as
new file mode 100644
index 00000000..9cb23b89
--- /dev/null
+++ b/src/mx/states/IOverride.as
@@ -0,0 +1,13 @@
+package mx.states
+{
+ import flash.display.DisplayObject;
+
+ public interface IOverride
+ {
+
+ function initialize():void;
+ function apply(parent:Object):void;
+ function remove(parent:Object):void;
+
+ }
+}
\ No newline at end of file
diff --git a/src/mx/states/OverrideBase.as b/src/mx/states/OverrideBase.as
new file mode 100644
index 00000000..c01c2827
--- /dev/null
+++ b/src/mx/states/OverrideBase.as
@@ -0,0 +1,47 @@
+package mx.states
+{
+
+ import flash.events.EventDispatcher;
+
+ public class OverrideBase extends EventDispatcher //implements IOverride
+ {
+
+ public function initialize():void {
+
+ }
+
+ public function apply(parent:Object):void {
+
+ }
+
+ public function remove(parent:Object):void {
+
+ }
+
+ /**
+ * @private
+ * @param parent The document level context for this override.
+ * @param target The component level context for this override.
+ */
+ protected function getOverrideContext(target:Object, parent:Object):Object
+ {
+ if (target == null)
+ return parent;
+
+ if (target is String)
+ return parent[target];
+
+ return target;
+ }
+
+
+ public function initializeFromObject(properties:Object):Object {
+ for (var p:String in properties)
+ {
+ this[p] = properties[p];
+ }
+ return Object(this);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/mx/states/SetProperty.as b/src/mx/states/SetProperty.as
new file mode 100644
index 00000000..fcccbe8a
--- /dev/null
+++ b/src/mx/states/SetProperty.as
@@ -0,0 +1,37 @@
+package mx.states
+{
+ import flash.display.DisplayObject;
+
+ public class SetProperty extends OverrideBase implements IOverride
+ {
+
+ public var name:String;
+ public var target:String;
+ public var value:*;
+
+ public var isBaseValueDataBound:Boolean;
+
+ private var oldValue:*;
+
+ override public function initialize():void {
+ trace("init");
+ }
+
+ override public function apply(parent:Object):void {
+ if(parent == null || target == null) { return; }
+ var item:Object = parent[target];
+ if(item == null) { return; }
+ oldValue = item[name];
+ item[name] = value;
+ }
+
+ override public function remove(parent:Object):void {
+ if(parent == null || target == null) { return; }
+ var item:Object = parent[target];
+ if(item == null) { return; }
+ item[name] = oldValue;
+ oldValue = null;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/mx/states/SetStyle.as b/src/mx/states/SetStyle.as
new file mode 100644
index 00000000..c974b3f4
--- /dev/null
+++ b/src/mx/states/SetStyle.as
@@ -0,0 +1,29 @@
+package mx.states
+{
+ import flash.display.DisplayObject;
+
+ public class SetStyle extends OverrideBase implements IOverride
+ {
+
+ public var name:String;
+ public var target:String;
+ public var value:*;
+
+ private var oldValue:*;
+
+ override public function initialize():void {
+ //trace("init");
+ }
+
+ override public function apply(parent:Object):void {
+ oldValue = parent[target].getStyle(name);
+ parent[target].setStyle(name, value);
+ }
+
+ override public function remove(parent:Object):void {
+ parent[target].setStyle(name, oldValue);
+ oldValue = null;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/mx/states/State.as b/src/mx/states/State.as
new file mode 100644
index 00000000..8fc901df
--- /dev/null
+++ b/src/mx/states/State.as
@@ -0,0 +1,291 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+// AdobePatentID="B770"
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.states
+{
+
+import flash.events.EventDispatcher;
+import mx.core.mx_internal;
+import mx.events.FlexEvent;
+
+use namespace mx_internal;
+
+//--------------------------------------
+// Events
+//--------------------------------------
+
+/**
+ * Dispatched after a view state has been entered.
+ *
+ * @eventType mx.events.FlexEvent.ENTER_STATE
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+[Event(name="enterState", type="mx.events.FlexEvent")]
+
+/**
+ * Dispatched just before a view state is exited.
+ * This event is dispatched before the changes
+ * to the default view state have been removed.
+ *
+ * @eventType mx.events.FlexEvent.EXIT_STATE
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+[Event(name="exitState", type="mx.events.FlexEvent")]
+
+//--------------------------------------
+// Other metadata
+//--------------------------------------
+
+[DefaultProperty("overrides")]
+
+/**
+ * The State class defines a view state, a particular view of a component.
+ * For example, a product thumbnail could have two view states;
+ * a base view state with minimal information, and a rich view state with
+ * additional information.
+ * The overrides property specifies a set of child classes
+ * to add or remove from the base view state, and properties, styles, and event
+ * handlers to set when the view state is in effect.
+ *
+ * You use the State class in the states property
+ * of Flex components.
+ * You can only specify a states property at the root of an
+ * application or a custom control, not on child controls.
You enable a view state by setting a component's
+ * currentState property.
The <mx:State> tag has the following attributes:
+ * <mx:State + * Properties + * basedOn="null" + * name="null" + * overrides="null" + * /> + *+ * + * @see mx.states.AddChild + * @see mx.states.RemoveChild + * @see mx.states.SetEventHandler + * @see mx.states.SetProperty + * @see mx.states.SetStyle + * @see mx.states.Transition + * + * @includeExample examples/StatesExample.mxml + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class State extends EventDispatcher +{ + //include "../core/Version.as"; + + import mx.core.mx_internal; + + /** + * @private + * Version string for this class. + */ + mx_internal static const VERSION:String = "4.1.0.16076"; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function State(properties:Object=null) + { + super(); + + // Initialize from object if provided. + for (var p:String in properties) + { + this[p] = properties[p]; + } + } + + //-------------------------------------------------------------------------- + // + // Variables + // + //-------------------------------------------------------------------------- + + /** + * @private + * Initialized flag + */ + private var initialized:Boolean = false; + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // basedOn + //---------------------------------- + + [Inspectable(category="General")] + + /** + * The name of the view state upon which this view state is based, or + *
null if this view state is not based on a named view state.
+ * If this value is null, the view state is based on a root
+ * state that consists of the properties, styles, event handlers, and
+ * children that you define for a component without using a State class.
+ *
+ * @default null
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var basedOn:String;
+
+ //----------------------------------
+ // name
+ //----------------------------------
+
+ [Inspectable(category="General")]
+
+ /**
+ * The name of the view state.
+ * State names must be unique for a given component.
+ * This property must be set.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public var name:String;
+
+ //----------------------------------
+ // overrides
+ //----------------------------------
+
+ [ArrayElementType("mx.states.IOverride")]
+ [Inspectable(category="General")]
+
+ /**
+ * The overrides for this view state, as an Array of objects that implement
+ * the IOverride interface. These overrides are applied in order when the
+ * state is entered, and removed in reverse order when the state is exited.
+ *
+ * The following Flex classes implement the IOverride interface and let you + * define the view state characteristics:
+ *The overrides property is the default property of the
+ * State class. You can omit the <mx:overrides> tag
+ * and its child <mx:Array>tag if you use MXML tag
+ * syntax to define the overrides.
If the selector parameter starts with a period (.),
+ * the returned CSSStyleDeclaration is a class selector and applies only to those instances
+ * whose styleName property specifies that selector
+ * (not including the period).
+ * For example, the class selector ".bigMargins"
+ * applies to any UIComponent whose styleName
+ * is "bigMargins".
If the selector parameter does not start with a period,
+ * the returned CSSStyleDeclaration is a type selector and applies to all instances
+ * of that type.
+ * For example, the type selector "Button"
+ * applies to all instances of Button and its subclasses.
The global selector is similar to a type selector
+ * and does not start with a period.
selector property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getStyleDeclaration(selector:String):CSSStyleDeclaration;
+
+ /**
+ * Sets the CSSStyleDeclaration object that stores the rules
+ * for the specified CSS selector.
+ *
+ * If the selector parameter starts with a period (.),
+ * the specified selector is a "class selector" and applies only to those instances
+ * whose styleName property specifies that selector
+ * (not including the period).
+ * For example, the class selector ".bigMargins"
+ * applies to any UIComponent whose styleName
+ * is "bigMargins".
If the selector parameter does not start with a period,
+ * the specified selector is a "type selector" and applies to all instances
+ * of that type.
+ * For example, the type selector "Button"
+ * applies to all instances of Button and its subclasses.
The global selector is similar to a type selector
+ * and does not start with a period.
true to force an immediate update of the styles; internally, Flex
+ * calls the styleChanged() method of UIComponent.
+ * Set to false to avoid an immediate update of the styles in the application.
+ *
+ * The styles will be updated the next time one of the following methods is called with
+ * the update property set to true:
+ *
clearStyleDeclaration()loadStyleDeclarations()setStyleDeclaration()unloadStyleDeclarations()Typically, if you call the one of these methods multiple times,
+ * you set this property to true only on the last call,
+ * so that Flex does not call the styleChanged() method multiple times.
If you call the getStyle() method, Flex returns the style value
+ * that was last applied to the UIComponent through a call to the styleChanged() method.
+ * The component's appearance might not reflect the value returned by the getStyle() method. This occurs
+ * because one of these style declaration methods might not yet have been called with the
+ * update property set to true.
If the specified selector is a class selector (for example, ".bigMargins" or ".myStyle"),
+ * you must be sure to start the
+ * selector property with a period (.).
If the specified selector is a type selector (for example, "Button"), do not start the
+ * selector property with a period.
The global selector is similar to a type selector
+ * and does not start with a period.
true to force an immediate update of the styles.
+ * Set to false to avoid an immediate update of the styles in the application.
+ * For more information about this method, see the description in the setStyleDeclaration()
+ * method.
+ *
+ * @see #setStyleDeclaration()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function clearStyleDeclaration(selector:String, update:Boolean):void;
+
+ /**
+ * Adds to the list of styles that can inherit values
+ * from their parents.
+ *
+ * Note: Ensure that you avoid using duplicate style names, as name + * collisions can result in decreased performance if a style that is + * already used becomes inheriting.
+ * + * @param styleName The name of the style that is added to the list of styles that can inherit values. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + function registerInheritingStyle(styleName:String):void; + + /** + * Tests to see if a style is inheriting. + * + * @param styleName The name of the style that you test to see if it is inheriting. + * + * @return Returnstrue if the specified style is inheriting.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function isInheritingStyle(styleName:String):Boolean;
+
+ /**
+ * Test to see if a TextFormat style is inheriting.
+ *
+ * @param styleName The name of the style that you test to see if it is inheriting.
+ *
+ * @return Returns true if the specified TextFormat style
+ * is inheriting.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function isInheritingTextFormatStyle(styleName:String):Boolean;
+
+ /**
+ * Adds to the list of styles which may affect the measured size
+ * of the component.
+ * When one of these styles is set with setStyle(),
+ * the invalidateSize() method is automatically called on the component
+ * to make its measured size get recalculated later.
+ *
+ * @param styleName The name of the style that you add to the list.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function registerSizeInvalidatingStyle(styleName:String):void;
+
+ /**
+ * Tests to see if a style changes the size of a component.
+ *
+ * When one of these styles is set with the setStyle() method,
+ * the invalidateSize() method is automatically called on the component
+ * to make its measured size get recalculated later.
true if the specified style is one
+ * which may affect the measured size of the component.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function isSizeInvalidatingStyle(styleName:String):Boolean;
+
+ /**
+ * Adds to the list of styles which may affect the measured size
+ * of the component's parent container.
+ * When one of these styles is set with setStyle(),
+ * the invalidateSize() method is automatically called on the component's
+ * parent container to make its measured size get recalculated
+ * later.
When one of these styles is set with setStyle(),
+ * the invalidateSize() method is automatically called on the component's
+ * parent container to make its measured size get recalculated
+ * later.
true if the specified style is one
+ * which may affect the measured size of the component's
+ * parent container.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function isParentSizeInvalidatingStyle(styleName:String):Boolean;
+
+ /**
+ * Adds to the list of styles which may affect the appearance
+ * or layout of the component's parent container.
+ * When one of these styles is set with setStyle(),
+ * the invalidateDisplayList() method is auomatically called on the component's
+ * parent container to make it redraw and/or relayout its children.
+ *
+ * @param styleName The name of the style to register.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function registerParentDisplayListInvalidatingStyle(styleName:String):void;
+
+ /**
+ * Tests to see if this style affects the component's parent container in
+ * such a way as to require that the parent container redraws itself when this style changes.
+ *
+ * When one of these styles is set with setStyle(),
+ * the invalidateDisplayList() method is auomatically called on the component's
+ * parent container to make it redraw and/or relayout its children.
true if the specified style is one
+ * which may affect the appearance or layout of the component's
+ * parent container.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function isParentDisplayListInvalidatingStyle(styleName:String):Boolean;
+
+ /**
+ * Adds a color name to the list of aliases for colors.
+ *
+ * @param colorName The name of the color to add to the list; for example, "blue".
+ * If you later access this color name, the value is not case-sensitive.
+ *
+ * @param colorValue Color value, for example, 0x0000FF.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function registerColorName(colorName:String, colorValue:uint):void;
+
+ /**
+ * Tests to see if the given String is an alias for a color value. For example,
+ * by default, the String "blue" is an alias for 0x0000FF.
+ *
+ * @param colorName The color name to test. This parameter is not case-sensitive.
+ *
+ * @return Returns true if colorName is an alias
+ * for a color.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function isColorName(colorName:String):Boolean;
+
+ /**
+ * Returns the numeric RGB color value that corresponds to the
+ * specified color string.
+ * The color string can be either a case-insensitive color name
+ * such as "red", "Blue", or
+ * "haloGreen", a hexadecimal value such as 0xFF0000, or a #-hexadecimal String
+ * such as "#FF0000".
+ *
+ * This method returns a uint, such as 4521830, that represents a color. You can convert
+ * this uint to a hexadecimal value by passing the numeric base (in this case, 16), to
+ * the uint class's toString() method, as the following example shows:
+ * import mx.styles.StyleManager;
+ * private function getNewColorName():void {
+ * StyleManager.registerColorName("soylentGreen",0x44FF66);
+ * trace(StyleManager.getColorName("soylentGreen").toString(16));
+ * }
+ *
+ *
+ * @param colorName The color name.
+ *
+ * @return Returns a uint that represents the color value or NOT_A_COLOR
+ * if the value of the colorName property is not an alias for a color.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getColorName(colorName:Object):uint;
+
+ /**
+ * Converts each element of the colors Array from a color name
+ * to a numeric RGB color value.
+ * Each color String can be either a case-insensitive color name
+ * such as "red", "Blue", or
+ * "haloGreen", a hexadecimal value such as 0xFF0000, or a #-hexadecimal String
+ * such as "#FF0000"..
+ *
+ * @param colors An Array of color names.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function getColorNames(colors:Array /* of Number or String */):void;
+
+ /**
+ * Determines if a specified parameter is a valid style property. For example:
+ *
+ *
+ * trace(StyleManager.isValidStyleValue(myButton.getStyle("color")).toString());
+ *
+ *
+ * This can be useful because some styles can be set to values
+ * such as 0, NaN,
+ * the empty String (""), or null, which can
+ * cause an if (value) test to fail.
getStyle() method call
+ * to this method, it returns true if the style
+ * was set and false if it was not set.
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function isValidStyleValue(value:*):Boolean;
+
+ /**
+ * Loads a style SWF.
+ *
+ * @param url Location of the style SWF.
+ *
+ * @param update Set to true to force
+ * an immediate update of the styles.
+ * Set to false to avoid an immediate update
+ * of the styles in the application.
+ * This parameter is optional and defaults to true
+ * For more information about this parameter, see the description
+ * in the setStyleDeclaration() method.
+ *
+ * @param trustContent Obsolete, no longer used.
+ * This parameter is optional and defaults to false.
+ *
+ * @param applicationDomain The ApplicationDomain passed to the
+ * load() method of the IModuleInfo that loads the style SWF.
+ * This parameter is optional and defaults to null.
+ *
+ * @param securityDomain The SecurityDomain passed to the
+ * load() method of the IModuleInfo that loads the style SWF.
+ * This parameter is optional and defaults to null.
+ *
+ * @return An IEventDispatcher implementation that supports
+ * StyleEvent.PROGRESS, StyleEvent.COMPLETE, and
+ * StyleEvent.ERROR.
+ *
+ * @see #setStyleDeclaration()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 4
+ */
+ function loadStyleDeclarations(
+ url:String, update:Boolean = true,
+ trustContent:Boolean = false,
+ applicationDomain:ApplicationDomain = null,
+ securityDomain:SecurityDomain = null):IEventDispatcher;
+
+ /**
+ * Unloads a style SWF.
+ *
+ * @param url Location of the style SWF.
+ * @param update Set to true to force an immediate update of the styles.
+ * Set to false to avoid an immediate update of the styles in the application.
+ * For more information about this method, see the description in the setStyleDeclaration()
+ * method.
+ *
+ * @see #setStyleDeclaration()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function unloadStyleDeclarations(
+ url:String, update:Boolean = true):void;
+
+ /**
+ * @private
+ * This method is called by code autogenerated by the MXML compiler,
+ * after StyleManager.styles is popuplated with CSSStyleDeclarations.
+ */
+ function initProtoChainRoots():void;
+
+ /**
+ * @private
+ * After an entire selector is added, replaced, or removed,
+ * this method updates all the DisplayList trees.
+ */
+ function styleDeclarationsChanged():void;
+}
+
+}
diff --git a/src/mx/styles/IStyleManager2.as b/src/mx/styles/IStyleManager2.as
index 5768e8b8..bd83fe90 100644
--- a/src/mx/styles/IStyleManager2.as
+++ b/src/mx/styles/IStyleManager2.as
@@ -1,10 +1,208 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
package mx.styles
{
- public interface IStyleManager2
- {
-
- function setStyleDeclaration(selector:String, styleDeclaration:CSSStyleDeclaration):void;
- function getStyleDeclaration(selector:String):CSSStyleDeclaration;
- //function initProtoChainRoots():void;
- }
-}
\ No newline at end of file
+
+import flash.events.IEventDispatcher;
+import flash.system.ApplicationDomain;
+import flash.system.SecurityDomain;
+
+/**
+ * The IStyleManager2 class manages the following:
+ * getStyleDeclaration() method to get the corresponding CSSStyleDeclaration object.
+ * Class selectors are prepended with a period.
+ *
+ * @return An Array of all of the selectors
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ function get selectors():Array;
+
+ //----------------------------------
+ // typeHierarchyCache
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ function get typeHierarchyCache():Object;
+
+ /**
+ * @private
+ */
+ function set typeHierarchyCache(value:Object):void;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Gets the list of style declarations for the given subject. The subject
+ * is the right most simple type selector in a potential selector chain.
+ *
+ * @param subject The style subject.
+ * @return Object map of StyleDeclarations for this subject. The object
+ * has four properties: class for class selectors,
+ * id for id selectors, pseudo for pseudo selectors and unconditional
+ * for selectors without conditions
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.6
+ */
+ function getStyleDeclarations(subject:String):Object;
+
+ /**
+ * Gets a CSSStyleDeclaration object that stores the rules
+ * for the specified CSS selector. The CSSStyleDeclaration object is
+ * created by merging the properties of the specified CSS selector in
+ * this style manager with the properties of any parent style managers.
+ *
+ * If the selector parameter starts with a period (.),
+ * the returned CSSStyleDeclaration is a class selector and applies only to those instances
+ * whose styleName property specifies that selector
+ * (not including the period).
+ * For example, the class selector ".bigMargins"
+ * applies to any UIComponent whose styleName
+ * is "bigMargins".
If the selector parameter does not start with a period,
+ * the returned CSSStyleDeclaration is a type selector and applies to all instances
+ * of that type.
+ * For example, the type selector "Button"
+ * applies to all instances of Button and its subclasses.
The global selector is similar to a type selector
+ * and does not start with a period.
selector property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function getMergedStyleDeclaration(selector:String):CSSStyleDeclaration;
+
+ /**
+ * @private
+ * Determines whether any of the selectors declared a pseudo selector
+ * for the given state. This is used to avoid unnecessary style
+ * regeneration between state changes.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function hasPseudoCondition(value:String):Boolean;
+
+ /**
+ * @private
+ * Determines whether any of the selectors registered with the style
+ * manager have been advanced selectors (descendant selector, id selector,
+ * non-global class selector, or pseudo selector).
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function hasAdvancedSelectors():Boolean;
+
+ /**
+ * @private
+ * In Flex 2, the static method StyleManager.loadStyleDeclarations()
+ * had three parameters and called loadStyleDeclarations()
+ * on IStyleManager.
+ * In Flex 3, the static method has four parameters and calls
+ * this method.
+ */
+ function loadStyleDeclarations2(
+ url:String, update:Boolean = true,
+ applicationDomain:ApplicationDomain = null,
+ securityDomain:SecurityDomain = null):IEventDispatcher;
+
+ /**
+ * @private
+ * Used in media query handling.
+ * @param value normalized media query string
+ * @returns true if valid media
+ */
+ function acceptMediaList(value:String):Boolean;
+}
+
+}
diff --git a/src/mx/styles/StyleManager.as b/src/mx/styles/StyleManager.as
deleted file mode 100644
index 2c66cd2c..00000000
--- a/src/mx/styles/StyleManager.as
+++ /dev/null
@@ -1,180 +0,0 @@
-package mx.styles
-{
- import flash.display.DisplayObject;
- import flash.display.Stage;
- import flash.events.Event;
- import flash.utils.Dictionary;
-
- import flight.observers.PropertyChange;
-
- import mx.core.IMXMLObject;
-
- import reflex.styles.IStylable;
-
- public class StyleManager implements IMXMLObject, IStyleManager2
- {
- protected static var collapseSpace:RegExp = new RegExp("\\t+| {2,}", "g");
- protected static var addMissingTypes:RegExp = new RegExp("(^| )(#|\\.|:)", "g");
- public static var selectors:Object = {};
- public static var declarations:Array = [];
- protected static var instance:IStyleManager2 = new StyleManager();
- protected static var targetChanges:Dictionary = new Dictionary(true);
- PropertyChange.addObserver(DisplayObject, "*", null, propertyChange);
-
- public static function getStyleManager(type:String):IStyleManager2
- {
- return instance;
- }
-
- //public function initProtoChainRoots():void {};
-
- /**
- * Grab a reference to the stage so we can set styles when items are
- * added.
- */
- public function initialized(document:Object, id:String):void
- {
- init(document.stage);
- }
-
- public static function init(stage:Stage):void
- {
- stage.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage, true);
- stage.addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage, true);
- }
-
- protected static function onAddedToStage(event:Event):void
- {
- var displayObject:DisplayObject = event.target as DisplayObject;
- updateStyles(displayObject);
- if (displayObject is IStylable) {
- displayObject.addEventListener("stateChange", onStateChange);
- }
- }
-
- protected static function onRemovedFromStage(event:Event):void
- {
- var displayObject:DisplayObject = event.target as DisplayObject;
- if (displayObject is IStylable) {
- displayObject.removeEventListener("stateChange", onStateChange);
- }
- }
-
- protected static function onStateChange(event:Event):void
- {
- var displayObject:DisplayObject = event.target as DisplayObject;
- updateStyles(displayObject);
- }
-
- protected static function updateStyles(displayObject:DisplayObject):void
- {
- var styles:Object = getStyles(displayObject);
- var i:String;
- var changed:Object = targetChanges[displayObject];
-
- // set classes first, then properties
- for (i in styles) {
- if (styles[i] is Class) {
- if (changed && changed[i.split(".").shift()]) continue;
- if (!applyStyle(displayObject, i.split("."), new styles[i]())) {
- trace(i, "was not able to be set on", displayObject);
- }
- }
- }
-
- // now set properties
- for (i in styles) {
- if ( !(styles[i] is Class) ) {
- if (changed && changed[i.split(".").shift()]) continue;
- if (!applyStyle(displayObject, i.split("."), styles[i])) {
- trace(i, "was not able to be set on", displayObject);
- }
- }
- }
- }
-
- protected static function applyStyle(obj:Object, props:Array, value:*):Boolean
- {
- var len:uint = props.length;
- try {
- for (var j:uint = 0; j < len; j++) {
- var name:String = props[j];
- if (j < len - 1) {
- obj = obj[name];
- } else {
- obj[name] = value;
- }
- }
- return true;
- } catch (e:Error) {trace(e);}
-
- return false;
- }
-
- public static function getStyles(obj:Object):Object
- {
- var declaration:CSSStyleDeclaration;
-
- var matches:Array = [];
- for each (declaration in declarations) {
- if (declaration.selector.match(obj)) {
- matches.push(declaration);
- }
- }
- matches.sortOn("specificity", Array.NUMERIC);
- var styles:Object = {};
- for each (declaration in matches) {
- var prefix:String = "";
- if (declaration.selector.property) {
- prefix = declaration.selector.property + ".";
- }
- mergeObjects(styles, declaration.styles, prefix);
- }
- return styles;
- }
-
- protected static function mergeObjects(mergeTo:Object, mergeFrom:Object, prefix:String = ""):Object
- {
- for (var name:String in mergeFrom) {
- mergeTo[prefix + name] = mergeFrom[name];
- }
- return mergeTo;
- }
-
- public static function registerInheritingStyle(...rest):void
- {
- trace("Registering inheriting style", rest);
- }
-
- public function getStyleDeclaration(selector:String):CSSStyleDeclaration
- {
- return null;
- }
-
-
- public function setStyleDeclaration(selector:String, styleDeclaration:CSSStyleDeclaration):void
- {
- trace("style declarations");
- declarations.push(styleDeclaration);
- }
-
-
- public static function clearStyleDeclaration(selector:String, unload:Boolean):void
- {
-
- }
-
- private static var propertyChangeReference:Function = propertyChange; // reference so doesn't slip out of PropertyChange memory
-
- protected static function propertyChange(target:Object, property:String, oldValue:*, newValue:*):void
- {
- trace(property, "has changed on", target);
- var changes:Object = targetChanges[target];
- if (changes == null) {
- targetChanges[target] = changes = {};
- }
-
- changes[property] = (newValue != null || !isNaN(newValue));
- }
- }
-}
\ No newline at end of file
diff --git a/src/mx/styles/StyleManagerImpl.as b/src/mx/styles/StyleManagerImpl.as
new file mode 100644
index 00000000..fc3dda27
--- /dev/null
+++ b/src/mx/styles/StyleManagerImpl.as
@@ -0,0 +1,1849 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.styles
+{
+
+import flash.display.DisplayObject;
+import flash.events.EventDispatcher;
+import flash.display.LoaderInfo;
+import flash.events.IEventDispatcher;
+import flash.events.TimerEvent;
+import flash.system.ApplicationDomain;
+import flash.system.SecurityDomain;
+import flash.utils.Timer
+import flash.utils.describeType;
+
+import mx.core.FlexVersion;
+import mx.core.IFlexModuleFactory;
+import mx.core.mx_internal;
+import mx.events.FlexChangeEvent;
+import mx.events.ModuleEvent;
+import mx.events.StyleEvent;
+import mx.managers.ISystemManager;
+import mx.managers.SystemManagerGlobals;
+import mx.modules.IModuleInfo;
+import mx.modules.ModuleManager
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+import mx.styles.IStyleModule;
+import mx.styles.IStyleManager2;
+import mx.events.Request;
+import mx.utils.MediaQueryParser;
+import flash.events.Event;
+
+use namespace mx_internal;
+
+[ExcludeClass]
+
+[ResourceBundle("styles")]
+
+/**
+ * @private
+ */
+public class StyleManagerImpl extends EventDispatcher implements IStyleManager2
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ //--------------------------------------------------------------------------
+ //
+ // Class variables
+ //
+ //--------------------------------------------------------------------------
+ /**
+ * @private
+ */
+ private static var instance:IStyleManager2;
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ public static function getInstance():IStyleManager2
+ {
+ if (!instance)
+ {
+ // In Flex 4 each application/module creates its own style manager.
+ // There will be no style manager if the application/module was compiled for
+ // Flex 3 compatibility. In that case create there will be no instance
+ // associated with the top-level application so create a new instance.
+ instance = IStyleManager2(IFlexModuleFactory(SystemManagerGlobals.topLevelSystemManagers[0]).
+ getImplementation("mx.styles::IStyleManager2"));
+
+ if (!instance)
+ instance = new StyleManagerImpl(SystemManagerGlobals.topLevelSystemManagers[0]);
+ }
+
+ return instance;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ *
+ * @param moduleFactory The module factory that is creating this instance. May not be null.
+ */
+ public function StyleManagerImpl(moduleFactory:IFlexModuleFactory)
+ {
+ super();
+
+ this.moduleFactory = moduleFactory;
+ this.moduleFactory.registerImplementation("mx.styles::IStyleManager2", this);
+
+ // get our parent styleManager
+ if (moduleFactory is DisplayObject)
+ {
+ var request:Request = new Request(Request.GET_PARENT_FLEX_MODULE_FACTORY_REQUEST);
+ DisplayObject(moduleFactory).dispatchEvent(request);
+ var parentModuleFactory:IFlexModuleFactory = request.value as IFlexModuleFactory;
+ if (parentModuleFactory)
+ {
+ _parent = IStyleManager2(parentModuleFactory.
+ getImplementation("mx.styles::IStyleManager2"));
+ if (_parent is IEventDispatcher)
+ {
+ IEventDispatcher(_parent).addEventListener(FlexChangeEvent.STYLE_MANAGER_CHANGE, styleManagerChangeHandler, false, 0, true);
+ }
+ }
+
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Used to assign the selectorIndex in CSSStyleDeclaration so we can track
+ * the order they were added to the StyleManager.
+ * MatchStyleDeclarations has to return the declarations in the order
+ * they were declared
+ */
+ private var selectorIndex:int = 0;
+
+ /**
+ * @private
+ */
+ private var mqp:MediaQueryParser;
+
+ /**
+ * @private
+ * Set of inheriting non-color styles.
+ * This is not the complete set from CSS.
+ * Some of the omitted we don't support at all,
+ * others may be added later as needed.
+ * The isInheritingTextFormatStyle() method queries this set.
+ */
+ private var inheritingTextFormatStyles:Object =
+ {
+ align: true,
+ bold: true,
+ color: true,
+ font: true,
+ indent: true,
+ italic: true,
+ size: true
+ };
+
+ /**
+ * @private
+ * Set of styles for which setStyle() causes
+ * invalidateSize() to be called on the component.
+ * The method registerSizeInvalidatingStyle() adds to this set
+ * and isSizeInvalidatingStyle() queries this set.
+ */
+ private var sizeInvalidatingStyles:Object =
+ {
+ alignmentBaseline: true,
+ baselineShift: true,
+ blockProgression: true,
+ borderStyle: true,
+ borderThickness: true,
+ breakOpportunity : true,
+ cffHinting: true,
+ columnCount: true,
+ columnGap: true,
+ columnWidth: true,
+ digitCase: true,
+ digitWidth: true,
+ direction: true,
+ dominantBaseline: true,
+ firstBaselineOffset: true,
+ fontAntiAliasType: true,
+ fontFamily: true,
+ fontGridFitType: true,
+ fontLookup: true,
+ fontSharpness: true,
+ fontSize: true,
+ fontStyle: true,
+ fontThickness: true,
+ fontWeight: true,
+ headerHeight: true,
+ horizontalAlign: true,
+ horizontalGap: true,
+ justificationRule: true,
+ justificationStyle: true,
+ kerning: true,
+ leading: true,
+ leadingModel: true,
+ letterSpacing: true,
+ ligatureLevel: true,
+ lineBreak: true,
+ lineHeight: true,
+ lineThrough: true,
+ listAutoPadding: true,
+ listStylePosition: true,
+ listStyleType: true,
+ locale: true,
+ marginBottom: true,
+ marginLeft: true,
+ marginRight: true,
+ marginTop: true,
+ paddingBottom: true,
+ paddingLeft: true,
+ paddingRight: true,
+ paddingTop: true,
+ paragraphEndIndent: true,
+ paragraphStartIndent: true,
+ paragraphSpaceAfter: true,
+ paragraphSpaceBefore: true,
+ renderingMode: true,
+ strokeWidth: true,
+ tabHeight: true,
+ tabWidth: true,
+ tabStops: true,
+ textAlign: true,
+ textAlignLast: true,
+ textDecoration: true,
+ textIndent: true,
+ textJustify: true,
+ textRotation: true,
+ tracking: true,
+ trackingLeft: true,
+ trackingRight: true,
+ typographicCase: true,
+ verticalAlign: true,
+ verticalGap: true,
+ wordSpacing:true,
+ whitespaceCollapse: true
+ }
+
+ /**
+ * @private
+ * Set of styles for which setStyle() causes
+ * invalidateSize() to be called on the component's parent.
+ * The method registerParentSizeInvalidatingStyle() adds to this set
+ * and isParentSizeInvalidatingStyle() queries this set.
+ */
+ private var parentSizeInvalidatingStyles:Object =
+ {
+ baseline: true,
+ bottom: true,
+ horizontalCenter: true,
+ left: true,
+ right: true,
+ top: true,
+ verticalCenter: true
+ }
+
+ /**
+ * @private
+ * Set of styles for which setStyle() causes
+ * invalidateDisplayList() to be called on the component's parent.
+ * The method registerParentDisplayListInvalidatingStyle() adds to this set
+ * and isParentDisplayListInvalidatingStyle() queries this set.
+ */
+ private var parentDisplayListInvalidatingStyles:Object =
+ {
+ baseline: true,
+ bottom: true,
+ horizontalCenter: true,
+ left: true,
+ right: true,
+ top: true,
+ verticalCenter: true
+ }
+
+ /**
+ * @private
+ * Set of color names.
+ * The method registerColorName() adds to this set
+ * and isColorName() queries this set.
+ * All color names in this set are lowercase in order to support
+ * case-insensitive mapping in the StyleManager methods getColorName(),
+ * getColorNames(), registerColorName(), and isColorName().
+ * We handle color names at runtime in a case-insensitive way
+ * because the MXML compiler does this at compile time,
+ * in conformance with the CSS spec.
+ */
+ private var colorNames:Object =
+ {
+ transparent: "transparent",
+ black: 0x000000,
+ blue: 0x0000FF,
+ green: 0x008000,
+ gray: 0x808080,
+ silver: 0xC0C0C0,
+ lime: 0x00FF00,
+ olive: 0x808000,
+ white: 0xFFFFFF,
+ yellow: 0xFFFF00,
+ maroon: 0x800000,
+ navy: 0x000080,
+ red: 0xFF0000,
+ purple: 0x800080,
+ teal: 0x008080,
+ fuchsia: 0xFF00FF,
+ aqua: 0x00FFFF,
+ magenta: 0xFF00FF,
+ cyan: 0x00FFFF,
+
+ // IMPORTANT: Theme colors must also be updated
+ // in the Flex compiler's CSS parser
+ // (in \src\java\macromedia\css\Descriptor.java)
+ // and possibly other places as well. Grep for them!
+ halogreen: 0x80FF4D,
+ haloblue: 0x009DFF,
+ haloorange: 0xFFB600,
+ halosilver: 0xAECAD9
+ };
+
+ /**
+ * @private
+ * Whether any advanced selectors have been registered with this style
+ * manager.
+ */
+ private var _hasAdvancedSelectors:Boolean;
+
+ /**
+ * @private
+ * A map of CSS pseudo states. If a pseudo selector exists for a
+ * particular state name, it is likely that styles need to be recalculated.
+ */
+ private var _pseudoCSSStates:Object;
+
+ /**
+ * @private
+ * A map of CSS selectors -- such as "global", "Button", and ".bigRed" --
+ * to CSSStyleDeclarations.
+ * This collection is accessed via getStyleDeclaration(),
+ * setStyleDeclaration(), and clearStyleDeclaration().
+ */
+ private var _selectors:Object = {};
+
+ /**
+ * @private
+ */
+ private var styleModules:Object = {};
+
+ /**
+ * @private
+ * A map of selector "subjects" to an ordered map of selector Strings and
+ * their associated CSSStyleDeclarations.
+ * The subject is the right most simple type selector in a potential chain
+ * of selectors.
+ */
+ private var _subjects:Object = {};
+
+ /**
+ * @private
+ * Used for accessing localized Error messages.
+ */
+ private var resourceManager:IResourceManager =
+ ResourceManager.getInstance();
+
+ /**
+ * @private
+ * Cache merged styles between this and parent.
+ */
+ private var mergedInheritingStylesCache:Object;
+
+ /**
+ * @private
+ * This style manager's flex module factory.
+ */
+ private var moduleFactory:IFlexModuleFactory;
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // parent
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _parent:IStyleManager2;
+
+ /**
+ * @private
+ *
+ * The style manager that is the parent of this StyleManager.
+ *
+ * @return the parent StyleManager or null if this is the top-level StyleManager.
+ */
+ public function get parent():IStyleManager2
+ {
+ return _parent;
+ }
+
+ //----------------------------------
+ // qualifiedTypeSelectors
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private static var _qualifiedTypeSelectors:Boolean = true;
+
+ public function get qualifiedTypeSelectors():Boolean
+ {
+ if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_4_0)
+ return false;
+
+ if (_qualifiedTypeSelectors)
+ return _qualifiedTypeSelectors;
+
+ if (parent)
+ return parent.qualifiedTypeSelectors;
+
+ return false;
+ }
+
+ public function set qualifiedTypeSelectors(value:Boolean):void
+ {
+ _qualifiedTypeSelectors = value;
+ }
+
+ //----------------------------------
+ // stylesRoot
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _stylesRoot:Object;
+
+ /**
+ * @private
+ * The root of all proto chains used for looking up styles.
+ * This object is initialized once by initProtoChainRoots() and
+ * then updated by calls to setStyle() on the global CSSStyleDeclaration.
+ * It is accessed by code that needs to construct proto chains,
+ * such as the initProtoChain() method of UIComponent.
+ */
+ public function get stylesRoot():Object
+ {
+ return _stylesRoot;
+ }
+ public function set stylesRoot(value:Object):void
+ {
+ _stylesRoot = value;
+ }
+
+ //----------------------------------
+ // inheritingStyles
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _inheritingStyles:Object = {};
+
+ /**
+ * @private
+ * Set of inheriting non-color styles.
+ * This is not the complete set from CSS.
+ * Some of the omitted we don't support at all,
+ * others may be added later as needed.
+ * The method registerInheritingStyle() adds to this set
+ * and isInheritingStyle() queries this set.
+ */
+ public function get inheritingStyles():Object
+ {
+ if (mergedInheritingStylesCache)
+ return mergedInheritingStylesCache;
+
+ var mergedStyles:Object = _inheritingStyles;
+
+ if (parent)
+ {
+ var otherStyles:Object = parent.inheritingStyles;
+
+ for (var obj:Object in otherStyles)
+ {
+ if (mergedStyles[obj] === undefined)
+ mergedStyles[obj] = otherStyles[obj];
+ }
+ }
+
+ mergedInheritingStylesCache = mergedStyles;
+
+ return mergedStyles;
+ }
+
+ public function set inheritingStyles(value:Object):void
+ {
+ _inheritingStyles = value;
+ mergedInheritingStylesCache = null;
+
+ if (hasEventListener(FlexChangeEvent.STYLE_MANAGER_CHANGE))
+ dispatchInheritingStylesChangeEvent();
+ }
+
+ //----------------------------------
+ // typeHierarchyCache
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _typeHierarchyCache:Object;
+
+ /**
+ * @private
+ */
+ public function get typeHierarchyCache():Object
+ {
+ if (_typeHierarchyCache == null)
+ _typeHierarchyCache = {};
+
+ return _typeHierarchyCache;
+ }
+
+ /**
+ * @private
+ */
+ public function set typeHierarchyCache(value:Object):void
+ {
+ _typeHierarchyCache = value;
+ }
+
+ //----------------------------------
+ // typeSelectorCache
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _typeSelectorCache:Object;
+
+ /**
+ * @private
+ */
+ public function get typeSelectorCache():Object
+ {
+ if (_typeSelectorCache == null)
+ _typeSelectorCache = {};
+
+ return _typeSelectorCache;
+ }
+
+ /**
+ * @private
+ */
+ public function set typeSelectorCache(value:Object):void
+ {
+ _typeSelectorCache = value;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * This method is called by code autogenerated by the MXML compiler,
+ * after StyleManager.styles is popuplated with CSSStyleDeclarations.
+ */
+ public function initProtoChainRoots():void
+ {
+ if (!stylesRoot)
+ {
+ var style:CSSStyleDeclaration = getMergedStyleDeclaration("global");
+ if (style != null)
+ {
+ stylesRoot = style.addStyleToProtoChain({}, null);
+ }
+ }
+ }
+
+ /**
+ * Returns an array of strings of all CSS selectors registered with the StyleManager.
+ * Pass items in this array to the getStyleDeclaration function to get the corresponding CSSStyleDeclaration.
+ * Note that class selectors are prepended with a period.
+ *
+ * @return An array of all of the selectors
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get selectors():Array
+ {
+ var theSelectors:Array = [];
+ for (var i:String in _selectors)
+ theSelectors.push(i);
+
+ if (parent)
+ {
+ var otherSelectors:Array = parent.selectors;
+ for (i in otherSelectors)
+ theSelectors.push(i);
+ }
+
+ return theSelectors;
+ }
+
+ /**
+ * Determines whether any of the selectors registered with the style
+ * manager have been advanced selectors (descendant selector, id selector,
+ * non-global class selector, pseudo selector).
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function hasAdvancedSelectors():Boolean
+ {
+ if (_hasAdvancedSelectors)
+ return true;
+
+ if (parent)
+ return parent.hasAdvancedSelectors();
+
+ return false;
+ }
+
+ /**
+ * @private
+ * Determines whether at least one pseudo-condition has been specified for
+ * the given state.
+ */
+ public function hasPseudoCondition(cssState:String):Boolean
+ {
+ if (_pseudoCSSStates != null && _pseudoCSSStates[cssState] != null)
+ return true;
+
+ if (parent)
+ return parent.hasPseudoCondition(cssState);
+
+ return false;
+ }
+
+ private static var propNames:Array = ["class", "id", "pseudo", "unconditional"];
+
+ /**
+ * Retrieve all style declarations applicable to this subject. The subject
+ * is the right most simple type selector in a selector chain. Returns a
+ * map of selectors with four properties: class for class selectors,
+ * id for id selectors, pseudo for pseudo selectors and unconditional
+ * for selectors without conditions
+ *
+ *
+ * @param subject The subject of the style declaration's selector.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function getStyleDeclarations(subject:String):Object
+ {
+ // For Flex 3 and earlier, if we were passed a subject with a package
+ // name, such as "mx.controls.Button", strip off the package name
+ // leaving just "Button" and look for that subject.
+ if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_4_0)
+ {
+ if (subject.charAt(0) != ".")
+ {
+ var index:int = subject.lastIndexOf(".");
+ if (index != -1)
+ subject = subject.substr(index + 1);
+ }
+ }
+
+ // NOTE: It's important the parent declarations come before this style
+ // manager's styles because the order here is the order they are added to the
+ // prototype chain.
+ var theSubjects:Object = null;
+
+ if (parent)
+ theSubjects = parent.getStyleDeclarations(subject);
+
+ var subjectsObject:Object = _subjects[subject];
+ if (!theSubjects)
+ {
+ if (subjectsObject)
+ theSubjects = subjectsObject;
+ }
+ else if (subjectsObject)
+ {
+ var mergedSubjects:Object = {};
+ for each (var prop:String in propNames)
+ {
+ mergedSubjects[prop] = subjectsObject[prop];
+ }
+ mergedSubjects.parent = theSubjects;
+ theSubjects = mergedSubjects;
+ }
+
+ return theSubjects;
+ }
+
+ private function isUnique(element:*, index:int, arr:Array):Boolean {
+ return (arr.indexOf(element) >= 0);
+ }
+
+ /**
+ * Gets the CSSStyleDeclaration object that stores the rules
+ * for the specified CSS selector.
+ *
+ * If the selector parameter starts with a period (.),
+ * the returned CSSStyleDeclaration is a class selector and applies only to those instances
+ * whose styleName property specifies that selector
+ * (not including the period).
+ * For example, the class selector ".bigMargins"
+ * applies to any UIComponent whose styleName
+ * is "bigMargins".
If the selector parameter does not start with a period,
+ * the returned CSSStyleDeclaration is a type selector and applies to all instances
+ * of that type.
+ * For example, the type selector "Button"
+ * applies to all instances of Button and its subclasses.
The global selector is similar to a type selector
+ * and does not start with a period.
selector property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function getStyleDeclaration(selector:String):CSSStyleDeclaration
+ {
+ // For Flex 3 and earlier, if we were passed a selector with a package
+ // name, such as "mx.controls.Button", strip off the package name
+ // leaving just "Button" and look for that type selector.
+ if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_4_0)
+ {
+ if (selector.charAt(0) != ".")
+ {
+ var index:int = selector.lastIndexOf(".");
+ if (index != -1)
+ selector = selector.substr(index + 1);
+ }
+ }
+
+ return _selectors[selector];
+ }
+
+ /**
+ * Gets a CSSStyleDeclaration object that stores the rules
+ * for the specified CSS selector. The CSSStyleDeclaration object is the created by merging
+ * the properties of the specified CSS selector of this style manager with all of the parent
+ * style managers.
+ *
+ *
+ * If this style manager contains a style declaration for the given selector, its style properties
+ * will be updated with properties from the parent style manager's merged style declaration. If
+ * this style manager does not have a style declaration for a given selector, the parent's merged
+ * style declaration will be set into this style manager depending on the value of the
+ * setSelector parameter.
+ *
If the selector parameter starts with a period (.),
+ * the returned CSSStyleDeclaration is a class selector and applies only to those instances
+ * whose styleName property specifies that selector
+ * (not including the period).
+ * For example, the class selector ".bigMargins"
+ * applies to any UIComponent whose styleName
+ * is "bigMargins".
If the selector parameter does not start with a period,
+ * the returned CSSStyleDeclaration is a type selector and applies to all instances
+ * of that type.
+ * For example, the type selector "Button"
+ * applies to all instances of Button and its subclasses.
The global selector is similar to a type selector
+ * and does not start with a period.
selector property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 4
+ */
+ public function getMergedStyleDeclaration(selector:String):CSSStyleDeclaration
+ {
+ var style:CSSStyleDeclaration = getStyleDeclaration(selector);
+ var parentStyle:CSSStyleDeclaration = null;
+
+ // If we have a parent, get its style and merge them with our style.
+ if (parent)
+ parentStyle = parent.getMergedStyleDeclaration(selector);
+
+ if (style || parentStyle)
+ {
+ style = new CSSMergedStyleDeclaration(style, parentStyle,
+ style ? style.selectorString : parentStyle.selectorString, this, false);
+ }
+
+ return style;
+ }
+
+ /**
+ * Sets the CSSStyleDeclaration object that stores the rules
+ * for the specified CSS selector.
+ *
+ * If the selector parameter starts with a period (.),
+ * the specified selector is a class selector and applies only to those instances
+ * whose styleName property specifies that selector
+ * (not including the period).
+ * For example, the class selector ".bigMargins"
+ * applies to any UIComponent whose styleName
+ * is "bigMargins".
If the selector parameter does not start with a period,
+ * the specified selector is a "type selector" and applies to all instances
+ * of that type.
+ * For example, the type selector "Button"
+ * applies to all instances of Button and its subclasses.
The global selector is similar to a type selector
+ * and does not start with a period.
Note that the provided selector will update the selector and subject + * of the styleDeclaration to keep them in sync.
+ * + * @param selector The name of the CSS selector. + * @param styleDeclaration The new style declaration. + * @param update Set totrue to force an immediate update of the styles.
+ * Set to false to avoid an immediate update of the styles in the application.
+ * The styles will be updated the next time this method or the clearStyleDeclaration() method
+ * is called with the update property set to true.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function setStyleDeclaration(selector:String,
+ styleDeclaration:CSSStyleDeclaration,
+ update:Boolean):void
+ {
+ // For Flex 3 and earlier, if we were passed a selector with a package
+ // name, such as "mx.controls.Button", strip off the package name
+ // leaving just "Button" and look for that type selector.
+ if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_4_0)
+ {
+ if (selector.charAt(0) != ".")
+ {
+ var index:int = selector.lastIndexOf(".");
+ if (index != -1)
+ selector = selector.substr(index + 1);
+ }
+ }
+
+ // Populate the selectors Array for this style declaration
+ styleDeclaration.selectorRefCount++;
+ styleDeclaration.selectorIndex = selectorIndex++;
+ _selectors[selector] = styleDeclaration;
+
+ // We also index by subject to help match advanced selectors
+ var subject:String = styleDeclaration.subject;
+ if (selector)
+ {
+ if (!styleDeclaration.subject)
+ {
+ // If the styleDeclaration does not yet have a subject we
+ // update its selector to keep it in sync with the provided
+ // selector.
+ styleDeclaration.selectorString = selector;
+ subject = styleDeclaration.subject;
+ }
+ else if (selector != styleDeclaration.selectorString)
+ {
+ // The styleDeclaration does not match the provided selector, so
+ // we ignore the subject on the styleDeclaration and try to
+ // determine the subject from the selector
+ var firstChar:String = selector.charAt(0);
+ if (firstChar == "." || firstChar == ":" || firstChar == "#")
+ {
+ subject = "*";
+ }
+ else
+ {
+ // TODO: Support parsing Advanced CSS selectors for a
+ // subject...
+ subject = selector;
+ }
+
+ // Finally, we update the styleDeclaration's selector to keep
+ // it in sync with the provided selector.
+ styleDeclaration.selectorString = selector;
+ }
+ }
+
+ if (subject != null)
+ {
+ // determine the kind of selector and add it to the appropriate
+ // bin of selectors for this subject
+ var kind:String = styleDeclaration.selector.conditions ?
+ styleDeclaration.selector.conditions[0].kind :
+ "unconditional";
+ var declarations:Object = _subjects[subject];
+ if (declarations == null)
+ {
+ declarations = {};
+ declarations[kind] = [styleDeclaration];
+ _subjects[subject] = declarations;
+ }
+ else
+ {
+ var declarationList:Array = declarations[kind] as Array;
+ if (declarationList == null)
+ declarations[kind] = [styleDeclaration];
+ else
+ declarationList.push(styleDeclaration);
+ }
+ }
+
+ // Also remember subjects that have pseudo-selectors to optimize
+ // styles during component state changes.
+ var pseudoCondition:String = styleDeclaration.getPseudoCondition();
+ if (pseudoCondition != null)
+ {
+ if (_pseudoCSSStates == null)
+ _pseudoCSSStates = {};
+
+ _pseudoCSSStates[pseudoCondition] = true;
+ }
+
+ // Record whether this is an advanced selector so that style declaration
+ // look up can be optimized for when no advanced selectors have been
+ // declared
+ if (styleDeclaration.isAdvanced())
+ _hasAdvancedSelectors = true;
+
+ // Flush cache and start over.
+ if (_typeSelectorCache)
+ _typeSelectorCache = {};
+
+ if (update)
+ styleDeclarationsChanged();
+ }
+
+ /**
+ * Clears the CSSStyleDeclaration object that stores the rules
+ * for the specified CSS selector.
+ *
+ * If the specified selector is a class selector (for example, ".bigMargins" or ".myStyle"),
+ * you must be sure to start the
+ * selector property with a period (.).
If the specified selector is a type selector (for example, "Button"), do not start the
+ * selector property with a period.
The global selector is similar to a type selector
+ * and does not start with a period.
true to force an immediate update of the styles.
+ * Set to false to avoid an immediate update of the styles in the application.
+ * The styles will be updated the next time this method or the setStyleDeclaration() method is
+ * called with the update property set to true.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function clearStyleDeclaration(selector:String,
+ update:Boolean):void
+ {
+ var styleDeclaration:CSSStyleDeclaration =
+ getStyleDeclaration(selector);
+
+ if (styleDeclaration && styleDeclaration.selectorRefCount > 0)
+ styleDeclaration.selectorRefCount--;
+
+ // Clear out legacy selectors map
+ delete _selectors[selector];
+
+ // Clear out matching decls from our selectors stored by subject
+ var decls:Array;
+ var i:int;
+ var decl:CSSStyleDeclaration;
+
+ if (styleDeclaration && styleDeclaration.subject)
+ {
+ decls = _subjects[styleDeclaration.subject] as Array;
+ if (decls)
+ {
+ // Work from the back of the array so we can remove elements
+ // as we go.
+ for (i = decls.length - 1; i >= 0; i--)
+ {
+ decl = decls[i];
+ if (decl && decl.selectorString == selector)
+ {
+ if (decls.length == 1)
+ delete _subjects[styleDeclaration.subject];
+ else
+ decls.splice(i, 1);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Without a subject, we start searching all declarations for this
+ // selector, clear out matching selectors if found and then assume
+ // this we can limit our search to this subject and stop looking.
+ var matchingSubject:Boolean = false;
+ for each (decls in _subjects)
+ {
+ if (decls)
+ {
+ // Work from the back of the array so we can remove elements
+ // as we go.
+ for (i = decls.length - 1; i >= 0; i--)
+ {
+ decl = decls[i];
+ if (decl && decl.selectorString == selector)
+ {
+ matchingSubject = true;
+ if (decls.length == 1)
+ delete _subjects[decl.subject];
+ else
+ decls.splice(i, 1);
+ }
+ }
+
+ if (matchingSubject)
+ break;
+ }
+ }
+ }
+
+ if (update)
+ styleDeclarationsChanged();
+ }
+
+ /**
+ * @private
+ * After an entire selector is added, replaced, or removed,
+ * this method updates all the DisplayList trees.
+ */
+ public function styleDeclarationsChanged():void
+ {
+ var sms:Array /* of SystemManager */ =
+ SystemManagerGlobals.topLevelSystemManagers;
+ var n:int = sms.length;
+ for (var i:int = 0; i < n; i++)
+ {
+ // Type as Object to avoid dependency on SystemManager or WindowedSystemManager
+ var sm:ISystemManager = sms[i];
+ var cm:Object = sm.getImplementation("mx.managers::ISystemManagerChildManager");
+ Object(cm).regenerateStyleCache(true);
+ Object(cm).notifyStyleChangeInChildren(null, true);
+ }
+ }
+
+ /**
+ * Adds to the list of styles that can inherit values
+ * from their parents.
+ *
+ * Note: Ensure that you avoid using duplicate style names, as name + * collisions can result in decreased performance if a style that is + * already used becomes inheriting.
+ * + * @param styleName The name of the style that is added to the list of styles that can inherit values. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function registerInheritingStyle(styleName:String):void + { + if (_inheritingStyles[styleName] != true) + { + _inheritingStyles[styleName] = true; + mergedInheritingStylesCache = null; + + if (hasEventListener(FlexChangeEvent.STYLE_MANAGER_CHANGE)) + dispatchInheritingStylesChangeEvent(); + } + } + + /** + * Tests to see if a style is inheriting. + * + * @param styleName The name of the style that you test to see if it is inheriting. + * + * @return Returnstrue if the specified style is inheriting.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function isInheritingStyle(styleName:String):Boolean
+ {
+ if (mergedInheritingStylesCache)
+ return mergedInheritingStylesCache[styleName] == true;
+
+ if (_inheritingStyles[styleName] == true)
+ return true;
+
+ if (parent && parent.isInheritingStyle(styleName))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Test to see if a TextFormat style is inheriting.
+ *
+ * @param styleName The name of the style that you test to see if it is inheriting.
+ *
+ * @return Returns true if the specified TextFormat style
+ * is inheriting.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function isInheritingTextFormatStyle(styleName:String):Boolean
+ {
+ if (inheritingTextFormatStyles[styleName] == true)
+ return true;
+
+ if (parent && parent.isInheritingTextFormatStyle(styleName))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Adds to the list of styles which may affect the measured size
+ * of the component.
+ * When one of these styles is set with setStyle(),
+ * the invalidateSize() method is automatically called on the component
+ * to make its measured size get recalculated later.
+ *
+ * @param styleName The name of the style that you add to the list.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function registerSizeInvalidatingStyle(styleName:String):void
+ {
+ sizeInvalidatingStyles[styleName] = true;
+ }
+
+ /**
+ * Tests to see if a style changes the size of a component.
+ *
+ * When one of these styles is set with the setStyle() method,
+ * the invalidateSize() method is automatically called on the component
+ * to make its measured size get recalculated later.
true if the specified style is one
+ * which may affect the measured size of the component.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function isSizeInvalidatingStyle(styleName:String):Boolean
+ {
+ if (sizeInvalidatingStyles[styleName] == true)
+ return true;
+
+ if (parent && parent.isSizeInvalidatingStyle(styleName))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Adds to the list of styles which may affect the measured size
+ * of the component's parent container.
+ * When one of these styles is set with setStyle(),
+ * the invalidateSize() method is automatically called on the component's
+ * parent container to make its measured size get recalculated
+ * later.
When one of these styles is set with setStyle(),
+ * the invalidateSize() method is automatically called on the component's
+ * parent container to make its measured size get recalculated
+ * later.
true if the specified style is one
+ * which may affect the measured size of the component's
+ * parent container.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function isParentSizeInvalidatingStyle(styleName:String):Boolean
+ {
+ if (parentSizeInvalidatingStyles[styleName] == true)
+ return true;
+
+ if (parent && parent.isParentSizeInvalidatingStyle(styleName))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Adds to the list of styles which may affect the appearance
+ * or layout of the component's parent container.
+ * When one of these styles is set with setStyle(),
+ * the invalidateDisplayList() method is auomatically called on the component's
+ * parent container to make it redraw and/or relayout its children.
+ *
+ * @param styleName The name of the style to register.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function registerParentDisplayListInvalidatingStyle(
+ styleName:String):void
+ {
+ parentDisplayListInvalidatingStyles[styleName] = true;
+ }
+
+ /**
+ * Tests to see if this style affects the component's parent container in
+ * such a way as to require that the parent container redraws itself when this style changes.
+ *
+ * When one of these styles is set with setStyle(),
+ * the invalidateDisplayList() method is auomatically called on the component's
+ * parent container to make it redraw and/or relayout its children.
true if the specified style is one
+ * which may affect the appearance or layout of the component's
+ * parent container.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function isParentDisplayListInvalidatingStyle(
+ styleName:String):Boolean
+ {
+ if (parentDisplayListInvalidatingStyles[styleName] == true)
+ return true;
+
+ if (parent && parent.isParentDisplayListInvalidatingStyle(styleName))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Adds a color name to the list of aliases for colors.
+ *
+ * @param colorName The name of the color to add to the list; for example, "blue".
+ * If you later access this color name, the value is not case-sensitive.
+ *
+ * @param colorValue Color value, for example, 0x0000FF.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function registerColorName(colorName:String, colorValue:uint):void
+ {
+ colorNames[colorName.toLowerCase()] = colorValue;
+ }
+
+ /**
+ * Tests to see if the given String is an alias for a color value. For example,
+ * by default, the String "blue" is an alias for 0x0000FF.
+ *
+ * @param colorName The color name to test. This parameter is not case-sensitive.
+ *
+ * @return Returns true if colorName is an alias
+ * for a color.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function isColorName(colorName:String):Boolean
+ {
+ if (colorNames[colorName.toLowerCase()] !== undefined)
+ return true;
+
+ if (parent && parent.isColorName(colorName))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Returns the numeric RGB color value that corresponds to the
+ * specified color string.
+ * The color string can be either a case-insensitive color name
+ * such as "red", "Blue", or
+ * "haloGreen", a hexadecimal value such as 0xFF0000, or a #-hexadecimal String
+ * such as "#FF0000".
+ *
+ * This method returns a uint, such as 4521830, that represents a color. You can convert
+ * this uint to a hexadecimal value by passing the numeric base (in this case, 16), to
+ * the uint class's toString() method, as the following example shows:
+ * import mx.styles.StyleManager;
+ * private function getNewColorName():void {
+ * StyleManager.registerColorName("soylentGreen",0x44FF66);
+ * trace(StyleManager.getColorName("soylentGreen").toString(16));
+ * }
+ *
+ *
+ * @param colorName The color name.
+ *
+ * @return Returns a uint that represents the color value or NOT_A_COLOR
+ * if the value of the colorName property is not an alias for a color.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function getColorName(colorName:Object):uint
+ {
+ var n:Number;
+
+ if (colorName is String)
+ {
+ if (colorName.charAt(0) == "#")
+ {
+ // Map "#77EE11" to 0x77EE11
+ n = Number("0x" + colorName.slice(1));
+ return isNaN(n) ? StyleManager.NOT_A_COLOR : uint(n);
+ }
+
+ if (colorName.charAt(1) == "x" && colorName.charAt(0) == '0')
+ {
+ // Map "#77EE11" to 0x77EE11
+ n = Number(colorName);
+ return isNaN(n) ? StyleManager.NOT_A_COLOR : uint(n);
+ }
+
+ // Map "red" or "Red" to 0xFF0000;
+ // Map "haloGreen" or "HaLoGrEeN" to 0x46FF00.
+ var c:* = colorNames[colorName.toLowerCase()];
+ if (c === undefined)
+ {
+ // If not found then try our parent
+ if (parent)
+ c = parent.getColorName(colorName);
+ }
+
+ if (c === undefined)
+ return StyleManager.NOT_A_COLOR;
+
+ return uint(c);
+ }
+
+ return uint(colorName);
+ }
+
+ /**
+ * Converts each element of the colors Array from a color name
+ * to a numeric RGB color value.
+ * Each color String can be either a case-insensitive color name
+ * such as "red", "Blue", or
+ * "haloGreen", a hexadecimal value such as 0xFF0000, or a #-hexadecimal String
+ * such as "#FF0000"..
+ *
+ * @param colors An Array of color names.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function getColorNames(colors:Array /* of Number or String */):void
+ {
+ if (!colors)
+ return;
+
+ var n:int = colors.length;
+ for (var i:int = 0; i < n; i++)
+ {
+ if ((colors[i] != null) && isNaN(colors[i]))
+ {
+ var colorNumber:uint = getColorName(colors[i]);
+ if (colorNumber != StyleManager.NOT_A_COLOR)
+ colors[i] = colorNumber;
+ }
+ }
+ }
+
+ /**
+ * Determines if a specified parameter is a valid style property. For example:
+ *
+ *
+ * trace(StyleManager.isValidStyleValue(myButton.getStyle("color")).toString());
+ *
+ *
+ * This can be useful because some styles can be set to values
+ * such as 0, NaN,
+ * the empty String (""), or null, which can
+ * cause an if (value) test to fail.
getStyle() method call
+ * to this method, it returns true if the style
+ * was set and false if it was not set.
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function isValidStyleValue(value:*):Boolean
+ {
+ // By convention, we don't allow style values to be undefined,
+ // so we can check for this as the "not set" value.
+ if (value !== undefined)
+ return true;
+
+ if (parent)
+ return parent.isValidStyleValue(value);
+
+ return false;
+ }
+
+ /**
+ * @private
+ */
+ public function loadStyleDeclarations(
+ url:String, update:Boolean = true,
+ trustContent:Boolean = false,
+ applicationDomain:ApplicationDomain = null,
+ securityDomain:SecurityDomain = null):
+ IEventDispatcher
+ {
+ return loadStyleDeclarations2(url, update, applicationDomain, securityDomain);
+ }
+
+ /**
+ * Loads a style SWF.
+ *
+ * @param url Location of the style SWF.
+ *
+ * @param update If true, all the DisplayList trees will be updated.
+ * The default is true.
+ *
+ * @return An IEventDispatcher implementation that supports
+ * StyleEvent.PROGRESS, StyleEvent.COMPLETE, and
+ * StyleEvent.ERROR.
+ *
+ * @see flash.system.SecurityDomain
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function loadStyleDeclarations2(
+ url:String, update:Boolean = true,
+ applicationDomain:ApplicationDomain = null,
+ securityDomain:SecurityDomain = null):
+ IEventDispatcher
+ {
+ var module:IModuleInfo = ModuleManager.getModule(url);
+ var thisStyleManager:IStyleManager2 = this;
+
+ var readyHandler:Function = function(moduleEvent:ModuleEvent):void
+ {
+ var styleModule:IStyleModule =
+ IStyleModule(moduleEvent.module.factory.create());
+
+ // Register the style module to use this style manager.
+ moduleEvent.module.factory.registerImplementation("mx.styles::IStyleManager2", thisStyleManager);
+ styleModule.setStyleDeclarations(thisStyleManager);
+ styleModules[moduleEvent.module.url].styleModule = styleModule;
+
+ if (update)
+ styleDeclarationsChanged();
+ };
+
+ module.addEventListener(ModuleEvent.READY, readyHandler,
+ false, 0, true);
+
+ var styleEventDispatcher:StyleEventDispatcher =
+ new StyleEventDispatcher(module);
+
+ var errorHandler:Function = function(moduleEvent:ModuleEvent):void
+ {
+ var errorText:String = resourceManager.getString(
+ "styles", "unableToLoad", [ moduleEvent.errorText, url ]);
+
+ if (styleEventDispatcher.willTrigger(StyleEvent.ERROR))
+ {
+ var styleEvent:StyleEvent = new StyleEvent(
+ StyleEvent.ERROR, moduleEvent.bubbles, moduleEvent.cancelable);
+ styleEvent.bytesLoaded = 0;
+ styleEvent.bytesTotal = 0;
+ styleEvent.errorText = errorText;
+ styleEventDispatcher.dispatchEvent(styleEvent);
+ }
+ else
+ {
+ throw new Error(errorText);
+ }
+ };
+
+ module.addEventListener(ModuleEvent.ERROR, errorHandler,
+ false, 0, true);
+
+ styleModules[url] =
+ new StyleModuleInfo(module, readyHandler, errorHandler);
+
+ // This Timer gives the loadStyleDeclarations() caller a chance
+ // to add event listeners to the return value, before the module
+ // is loaded.
+ var timer:Timer = new Timer(0);
+ var timerHandler:Function = function(event:TimerEvent):void
+ {
+ timer.removeEventListener(TimerEvent.TIMER, timerHandler);
+ timer.stop();
+ module.load(applicationDomain, securityDomain);
+ };
+
+ timer.addEventListener(TimerEvent.TIMER, timerHandler, false, 0, true);
+
+ timer.start();
+
+ return styleEventDispatcher;
+ }
+
+ /**
+ * Unloads a style SWF.
+ *
+ * @param url Location of the style SWF.
+ *
+ * @param update If true, all the DisplayList trees will be updated.
+ * The default is true.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function unloadStyleDeclarations(
+ url:String, update:Boolean = true):void
+ {
+ var styleModuleInfo:StyleModuleInfo = styleModules[url];
+ if (styleModuleInfo)
+ {
+ styleModuleInfo.styleModule.unload();
+
+ var module:IModuleInfo = styleModuleInfo.module;
+ module.unload();
+
+ module.removeEventListener(ModuleEvent.READY,
+ styleModuleInfo.readyHandler);
+ module.removeEventListener(ModuleEvent.ERROR,
+ styleModuleInfo.errorHandler);
+
+ styleModules[url] = null;
+ }
+
+ if (update)
+ styleDeclarationsChanged();
+ }
+
+
+ /**
+ * @private
+ */
+ private function dispatchInheritingStylesChangeEvent():void
+ {
+ var event:Event = new FlexChangeEvent(FlexChangeEvent.STYLE_MANAGER_CHANGE,
+ false, false, {property: "inheritingStyles"});
+ dispatchEvent(event);
+ }
+
+ /**
+ * @private
+ */
+ public function acceptMediaList(value:String):Boolean
+ {
+ if (!mqp)
+ {
+ mqp = MediaQueryParser.instance;
+ if (!mqp)
+ {
+ mqp = new MediaQueryParser(moduleFactory);
+ MediaQueryParser.instance = mqp;
+ }
+ }
+ return mqp.parse(value);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Event handlers
+ //
+ //--------------------------------------------------------------------------
+
+ private function styleManagerChangeHandler(event:FlexChangeEvent):void
+ {
+ if (!event.data)
+ return; // invalid message
+
+ var property:String = event.data["property"];
+
+ if (property == "inheritingStyles")
+ {
+ mergedInheritingStylesCache = null;
+ }
+
+ if (hasEventListener(FlexChangeEvent.STYLE_MANAGER_CHANGE))
+ dispatchEvent(event);
+ }
+}
+
+}
+
+import flash.events.EventDispatcher;
+import mx.events.ModuleEvent;
+import mx.events.StyleEvent;
+import mx.modules.IModuleInfo;
+import mx.styles.IStyleModule;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Helper class: StyleEventDispatcher
+//
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @private
+ */
+class StyleEventDispatcher extends EventDispatcher
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function StyleEventDispatcher(moduleInfo:IModuleInfo)
+ {
+ super();
+
+ moduleInfo.addEventListener(
+ ModuleEvent.PROGRESS, moduleInfo_progressHandler, false, 0, true);
+
+ moduleInfo.addEventListener(
+ ModuleEvent.READY, moduleInfo_readyHandler, false, 0, true);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Event handlers
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private function moduleInfo_progressHandler(event:ModuleEvent):void
+ {
+ var styleEvent:StyleEvent = new StyleEvent(
+ StyleEvent.PROGRESS, event.bubbles, event.cancelable);
+ styleEvent.bytesLoaded = event.bytesLoaded;
+ styleEvent.bytesTotal = event.bytesTotal;
+ dispatchEvent(styleEvent);
+ }
+
+ /**
+ * @private
+ */
+ private function moduleInfo_readyHandler(event:ModuleEvent):void
+ {
+ var styleEvent:StyleEvent = new StyleEvent(StyleEvent.COMPLETE);
+ styleEvent.bytesLoaded = event.bytesLoaded;
+ styleEvent.bytesTotal = event.bytesTotal;
+ dispatchEvent(styleEvent);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Helper class: StyleModuleInfo
+//
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @private
+ */
+class StyleModuleInfo
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function StyleModuleInfo(module:IModuleInfo,
+ readyHandler:Function,
+ errorHandler:Function)
+ {
+ super();
+
+ this.module = module;
+ this.readyHandler = readyHandler;
+ this.errorHandler = errorHandler;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // errorHandler
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ public var errorHandler:Function;
+
+ //----------------------------------
+ // readyHandler
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ public var readyHandler:Function;
+
+ //----------------------------------
+ // styleModule
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ public var styleModule:IStyleModule;
+
+ //----------------------------------
+ // module
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ public var module:IModuleInfo
+}
diff --git a/src/mx/utils/DescribeTypeCache.as b/src/mx/utils/DescribeTypeCache.as
new file mode 100644
index 00000000..427e6701
--- /dev/null
+++ b/src/mx/utils/DescribeTypeCache.as
@@ -0,0 +1,165 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.utils
+{
+
+import flash.utils.describeType;
+import flash.utils.getDefinitionByName;
+import flash.utils.getQualifiedClassName;
+import mx.binding.BindabilityInfo;
+
+[ExcludeClass]
+
+/**
+ * @private
+ * DescribeTypeCache is a convenience class that is used to
+ * cache the return values of flash.utils.describeType()
+ * so that calls made subsequent times return faster.
+ *
+ * This class also lets you set handler functions for specific value types.
+ * These will get called when the user tries to access these values on
+ * the DescribeTypeCacheRecord class.
+ *
+ * @see mx.utils.DescribeTypeCacheRecord
+ */
+public class DescribeTypeCache
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class initialization
+ //
+ //--------------------------------------------------------------------------
+
+ registerCacheHandler("bindabilityInfo", bindabilityInfoHandler);
+
+ //--------------------------------------------------------------------------
+ //
+ // Class variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private static var typeCache:Object = {};
+
+ /**
+ * @private
+ */
+ private static var cacheHandlers:Object = {};
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Calls flash.utils.describeType() for the first time and caches
+ * the return value so that subsequent calls return faster.
+ *
+ * @param o Can be either a string describing a fully qualified class name or any
+ * ActionScript value, including all available ActionScript types, object instances,
+ * primitive types (such as uint), and class objects.
+ *
+ * @return Returns the cached record.
+ *
+ * @see flash.utils#describeType()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function describeType(o:*):DescribeTypeCacheRecord
+ {
+ var className:String;
+ var cacheKey:String;
+
+ if (o is String)
+ cacheKey = className = o;
+ else
+ cacheKey = className = getQualifiedClassName(o);
+
+ //Need separate entries for describeType(Foo) and describeType(myFoo)
+ if (o is Class)
+ cacheKey += "$";
+
+ if (cacheKey in typeCache)
+ {
+ return typeCache[cacheKey];
+ }
+ else
+ {
+ if (o is String)
+ {
+ try
+ {
+ o = getDefinitionByName(o);
+ }
+ catch (error:ReferenceError)
+ {
+ // The o parameter doesn't refer to an ActionScript
+ // definition, it's just a string value.
+ }
+ }
+ var typeDescription:XML = flash.utils.describeType(o);
+ var record:DescribeTypeCacheRecord = new DescribeTypeCacheRecord();
+ record.typeDescription = typeDescription;
+ record.typeName = className;
+ typeCache[cacheKey] = record;
+
+ return record;
+ }
+ }
+
+ /**
+ * registerCacheHandler lets you add function handler for specific strings.
+ * These functions get called when the user refers to these values on a
+ * instance of DescribeTypeCacheRecord.
+ *
+ * @param valueName String that specifies the value for which the handler must be set.
+ * @param handler Function that should be called when user references valueName.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function registerCacheHandler(valueName:String, handler:Function):void
+ {
+ cacheHandlers[valueName] = handler;
+ }
+
+ /**
+ * @private
+ */
+ internal static function extractValue(valueName:String, record:DescribeTypeCacheRecord):*
+ {
+ if (valueName in cacheHandlers)
+ return cacheHandlers[valueName](record);
+
+ return undefined;
+ }
+
+ /**
+ * @private
+ */
+ private static function bindabilityInfoHandler(record:DescribeTypeCacheRecord):*
+ {
+ return new BindabilityInfo(record.typeDescription);
+ }
+}
+
+}
diff --git a/src/mx/utils/DescribeTypeCacheRecord.as b/src/mx/utils/DescribeTypeCacheRecord.as
new file mode 100644
index 00000000..2aae66e8
--- /dev/null
+++ b/src/mx/utils/DescribeTypeCacheRecord.as
@@ -0,0 +1,121 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.utils
+{
+
+import flash.utils.Proxy;
+import flash.utils.flash_proxy;
+
+use namespace flash_proxy;
+
+[ExcludeClass]
+
+/**
+ * @private
+ * This class represents a single cache entry, this gets created
+ * as part of the describeType method call on the
+ * DescribeTypeCache class.
+ */
+
+public dynamic class DescribeTypeCacheRecord extends Proxy
+{
+ //--------------------------------------------------------------------------
+ //
+ // Class variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private var cache:Object = {};
+
+ //--------------------------------------------------------------------------
+ //
+ // Class properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // typeDescription
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ public var typeDescription:XML;
+
+ //----------------------------------
+ // typeName
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ public var typeName:String;
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ public function DescribeTypeCacheRecord()
+ {
+ super();
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override flash_proxy function getProperty(name:*):*
+ {
+ var result:* = cache[name];
+
+ if (result === undefined)
+ {
+ result = DescribeTypeCache.extractValue(name, this);
+ cache[name] = result;
+ }
+
+ return result;
+ }
+
+ /**
+ * @private
+ */
+ override flash_proxy function hasProperty(name:*):Boolean
+ {
+ if (name in cache)
+ return true;
+
+ var value:* = DescribeTypeCache.extractValue(name, this);
+
+ if (value === undefined)
+ return false;
+
+ cache[name] = value;
+
+ return true;
+ }
+}
+
+}
diff --git a/src/mx/utils/IXMLNotifiable.as b/src/mx/utils/IXMLNotifiable.as
new file mode 100644
index 00000000..03f14bd9
--- /dev/null
+++ b/src/mx/utils/IXMLNotifiable.as
@@ -0,0 +1,35 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.utils
+{
+
+/**
+ * The IXMLNotifiable interface.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public interface IXMLNotifiable
+{
+ /**
+ * @private
+ */
+ function xmlNotification(currentTarget:Object,
+ type:String,
+ target:Object,
+ value:Object,
+ detail:Object):void;
+}
+
+}
\ No newline at end of file
diff --git a/src/mx/utils/MatrixUtil.as b/src/mx/utils/MatrixUtil.as
new file mode 100644
index 00000000..90c0a9b4
--- /dev/null
+++ b/src/mx/utils/MatrixUtil.as
@@ -0,0 +1,1738 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2003-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.utils
+{
+
+import flash.display.DisplayObject;
+import flash.geom.Matrix;
+import flash.geom.Matrix3D;
+import flash.geom.PerspectiveProjection;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+import flash.geom.Utils3D;
+import flash.geom.Vector3D;
+import flash.system.ApplicationDomain;
+import flash.utils.getDefinitionByName;
+
+import mx.core.mx_internal;
+
+use namespace mx_internal;
+
+[ExcludeClass]
+
+/**
+ * @private
+ * The MatrixUtil class is for internal use only.
+ * Class for matrix and geometric related math routines.
+ */
+public final class MatrixUtil
+{
+ include "../core/Version.as";
+
+ private static const RADIANS_PER_DEGREES:Number = Math.PI / 180;
+ mx_internal static var SOLUTION_TOLERANCE:Number = 0.1;
+ mx_internal static var MIN_MAX_TOLERANCE:Number = 0.1;
+
+ private static var staticPoint:Point = new Point();
+
+ // For use in getConcatenatedMatrix function
+ private static var fakeDollarParent:QName;
+ private static var uiComponentClass:Class;
+ private static var uiMovieClipClass:Class;
+ private static var usesMarshalling:Object;
+ private static var lastModuleFactory:Object;
+ private static var computedMatrixProperty:QName;
+ private static var $transformProperty:QName;
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Returns rotation value clamped between -180 and 180 degreeds.
+ * This mimicks the Flash player behavior.
+ */
+ public static function clampRotation(value:Number):Number
+ {
+ // Flash player doesn't handle values larger than 2^15 - 1 (FP-749).
+ if (value > 180 || value < -180)
+ {
+ value = value % 360;
+
+ if (value > 180)
+ value = value - 360;
+ else if (value < -180)
+ value = value + 360;
+ }
+ return value;
+ }
+
+ /**
+ * Returns a static Point object with the result.
+ * If matrix is null, point is untransformed.
+ */
+ public static function transformPoint(x:Number, y:Number, m:Matrix):Point
+ {
+ if (!m)
+ {
+ staticPoint.x = x;
+ staticPoint.y = y;
+ return staticPoint;
+ }
+
+ staticPoint.x = m.a * x + m.c * y + m.tx;
+ staticPoint.y = m.b * x + m.d * y + m.ty;
+ return staticPoint;
+ }
+
+ public static function composeMatrix(x:Number = 0,
+ y:Number = 0,
+ scaleX:Number = 1,
+ scaleY:Number = 1,
+ rotation:Number = 0,
+ transformX:Number = 0,
+ transformY:Number = 0):Matrix
+ {
+ var m:Matrix = new Matrix();
+ m.translate(-transformX, -transformY);
+ m.scale(scaleX, scaleY);
+ if (rotation != 0)
+ m.rotate(rotation / 180 * Math.PI);
+ m.translate(transformX + x, transformY + y);
+ return m;
+ }
+
+ /**
+ * Decompose a matrix into its component scale, rotation, and translation parts.
+ * The Vector of Numbers passed in the components parameter will be
+ * populated by this function with the component parts.
+ *
+ * @param components Vector which holds the component scale, rotation
+ * and translation values.
+ * x = components[0]
+ * y = components[1]
+ * rotation = components[2]
+ * scaleX = components[3]
+ * scaleY = components[4]
+ *
+ * @param matrix The matrix to decompose
+ * @param transformX The x value of the transform center
+ * @param transformY The y value of the transform center
+ */
+ public static function decomposeMatrix(components:Vector.rect and
+ * Rectangle(left, top, right - left, bottom - top).
+ * Note that if rect is non-null, it will be updated to reflect the return value.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function rectUnion(left:Number, top:Number, right:Number, bottom:Number,
+ rect:Rectangle):Rectangle
+ {
+ if (!rect)
+ return new Rectangle(left, top, right - left, bottom - top);
+
+ var minX:Number = Math.min(rect.left, left);
+ var minY:Number = Math.min(rect.top, top);
+ var maxX:Number = Math.max(rect.right, right);
+ var maxY:Number = Math.max(rect.bottom, bottom);
+
+ rect.x = minX;
+ rect.y = minY;
+ rect.width = maxX - minX;
+ rect.height = maxY - minY;
+ return rect;
+ }
+
+ /**
+ * Calculates the bounding box of a post-transformed ellipse.
+ *
+ * @param cx The x coordinate of the ellipse's center
+ * @param cy The y coordinate of the ellipse's center
+ * @param rx The horizontal radius of the ellipse
+ * @param ry The vertical radius of the ellipse
+ * @param matrix The transformation matrix.
+ * @param rect If non-null, rect will be updated to the union of rect and
+ * the segment bounding box.
+ * @return Returns the union of the passed in rect with the
+ * bounding box of the the post-transformed ellipse.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function getEllipseBoundingBox(cx:Number, cy:Number,
+ rx:Number, ry:Number,
+ matrix:Matrix,
+ rect:Rectangle = null):Rectangle
+ {
+ var a:Number = matrix.a;
+ var b:Number = matrix.b;
+ var c:Number = matrix.c;
+ var d:Number = matrix.d;
+
+ // Ellipse can be represented by the following parametric equations:
+ //
+ // (1) x = cx + rx * cos(t)
+ // (2) y = cy + ry * sin(t)
+ //
+ // After applying transformation with matrix m(a, c, b, d) we get:
+ //
+ // (3) x = a * cx + a * cos(t) * rx + c * cy + c * sin(t) * ry + m.tx
+ // (4) y = b * cx + b * cos(t) * rx + d * cy + d * sin(t) * ry + m.ty
+ //
+ // In (3) and (4) x and y are functions of a parameter t. To find the extremums we need
+ // to find where dx/dt and dy/dt reach zero:
+ //
+ // (5) dx/dt = - a * sin(t) * rx + c * cos(t) * ry
+ // (6) dy/dt = - b * sin(t) * rx + d * cos(t) * ry
+ // (7) dx/dt = 0 <=> sin(t) / cos(t) = (c * ry) / (a * rx);
+ // (8) dy/dt = 0 <=> sin(t) / cos(t) = (d * ry) / (b * rx);
+
+ if (rx == 0 && ry == 0)
+ {
+ var pt:Point = new Point(cx, cy);
+ pt = matrix.transformPoint(pt);
+ return rectUnion(pt.x, pt.y, pt.x, pt.y, rect);
+ }
+
+ var t:Number;
+ var t1:Number;
+
+ if (a * rx == 0)
+ t = Math.PI / 2;
+ else
+ t = Math.atan((c * ry) / (a * rx));
+
+ if (b * rx == 0)
+ t1 = Math.PI / 2;
+ else
+ t1 = Math.atan((d * ry) / (b * rx));
+
+ var x1:Number = a * Math.cos(t) * rx + c * Math.sin(t) * ry;
+ var x2:Number = -x1;
+ x1 += a * cx + c * cy + matrix.tx;
+ x2 += a * cx + c * cy + matrix.tx;
+
+ var y1:Number = b * Math.cos(t1) * rx + d * Math.sin(t1) * ry;
+ var y2:Number = -y1;
+ y1 += b * cx + d * cy + matrix.ty;
+ y2 += b * cx + d * cy + matrix.ty;
+
+ return rectUnion(Math.min(x1, x2), Math.min(y1, y2), Math.max(x1, x2), Math.max(y1, y2), rect);
+ }
+
+ /**
+ * @param x0 x coordinate of the first control point
+ * @param y0 y coordinate of the first control point
+ * @param x1 x coordinate of the second control point
+ * @param y1 y coordinate of the second control point
+ * @param x2 x coordinate of the third control point
+ * @param y2 y coordinate of the third control point
+ * @param sx The pre-transform scale factor for x coordinates.
+ * @param sy The pre-transform scale factor for y coordinates.
+ * @param matrix The transformation matrix. Can be null for identity transformation.
+ * @param rect If non-null, rect will be updated to the union of rect and
+ * the segment bounding box.
+ * @return Returns the union of the post-transformed quadratic
+ * bezier segment's axis aligned bounding box and the passed in rect.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ static public function getQBezierSegmentBBox(x0:Number, y0:Number,
+ x1:Number, y1:Number,
+ x2:Number, y2:Number,
+ sx:Number, sy:Number,
+ matrix:Matrix,
+ rect:Rectangle):Rectangle
+ {
+ var pt:Point;
+ pt = MatrixUtil.transformPoint(x0 * sx, y0 * sy, matrix);
+ x0 = pt.x;
+ y0 = pt.y;
+
+ pt = MatrixUtil.transformPoint(x1 * sx, y1 * sy, matrix);
+ x1 = pt.x;
+ y1 = pt.y;
+
+ pt = MatrixUtil.transformPoint(x2 * sx, y2 * sy, matrix);
+ x2 = pt.x;
+ y2 = pt.y;
+
+ var minX:Number = Math.min(x0, x2);
+ var maxX:Number = Math.max(x0, x2);
+
+ var minY:Number = Math.min(y0, y2);
+ var maxY:Number = Math.max(y0, y2);
+
+ var txDiv:Number = x0 - 2 * x1 + x2;
+ if (txDiv != 0)
+ {
+ var tx:Number = (x0 - x1) / txDiv;
+ if (0 <= tx && tx <= 1)
+ {
+ var x:Number = (1 - tx) * (1 - tx) * x0 + 2 * tx * (1 - tx) * x1 + tx * tx * x2;
+ minX = Math.min(x, minX);
+ maxX = Math.max(x, maxX);
+ }
+ }
+
+ var tyDiv:Number = y0 - 2 * y1 + y2;
+ if (tyDiv != 0)
+ {
+ var ty:Number = (y0 - y1) / tyDiv;
+ if (0 <= ty && ty <= 1)
+ {
+ var y:Number = (1 - ty) * (1 - ty) * y0 + 2 * ty * (1 - ty) * y1 + ty * ty * y2;
+ minY = Math.min(y, minY);
+ maxY = Math.max(y, maxY);
+ }
+ }
+
+ return rectUnion(minX, minY, maxX, maxY, rect);
+ }
+
+ /**
+ * @param width The width of the bounds to be transformed.
+ * @param height The height of the bounds to be transformed.
+ * @param matrix The transfomration matrix.
+ *
+ * @param vec If vec is non-null it will be set to the vector from the
+ * transformed bounds top left to the untransformed bounds top left
+ * in the coordinate space defined by matrix.
+ * This is useful if you want to align the transformed bounds to x,y
+ * by modifying the object's position. Moving the object by
+ * x + vec.x and y + vec.y respectively
+ * will offset the transformed bounds top left corner by x,y.
+ *
+ * @return Returns the transformed bounds. Note that the Point object returned will be reused
+ * by other MatrixUtil methods.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function transformSize(width:Number, height:Number, matrix:Matrix):Point
+ {
+ const a:Number = matrix.a;
+ const b:Number = matrix.b;
+ const c:Number = matrix.c;
+ const d:Number = matrix.d;
+
+ // transform point (0,0)
+ var x1:Number = 0;
+ var y1:Number = 0;
+
+ // transform point (width, 0)
+ var x2:Number = width * a;
+ var y2:Number = width * b;
+
+ // transform point (0, height)
+ var x3:Number = height * c;
+ var y3:Number = height * d;
+
+ // transform point (width, height)
+ var x4:Number = x2 + x3;
+ var y4:Number = y2 + y3;
+
+ var minX:Number = Math.min(Math.min(x1, x2), Math.min(x3, x4));
+ var maxX:Number = Math.max(Math.max(x1, x2), Math.max(x3, x4));
+ var minY:Number = Math.min(Math.min(y1, y2), Math.min(y3, y4));
+ var maxY:Number = Math.max(Math.max(y1, y2), Math.max(y3, y4));
+
+ staticPoint.x = maxX - minX;
+ staticPoint.y = maxY - minY;
+ return staticPoint;
+ }
+
+ /**
+ * @param width The width of the bounds to be transformed.
+ * @param height The height of the bounds to be transformed.
+ * @param matrix The transfomration matrix.
+ *
+ * @param topleft If topLeft is non-null it will be used as the origin of the bounds
+ * rectangle to be transformed. On return, it will be set to the top left of the rectangle
+ * after transformation.
+ *
+ * @return Returns the transformed width and height. Note that the Point object returned will be reused
+ * by other MatrixUtil methods.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function transformBounds(width:Number, height:Number, matrix:Matrix, topLeft:Point = null):Point
+ {
+ const a:Number = matrix.a;
+ const b:Number = matrix.b;
+ const c:Number = matrix.c;
+ const d:Number = matrix.d;
+
+ // transform point (0,0)
+ var x1:Number = 0;
+ var y1:Number = 0;
+
+ // transform point (width, 0)
+ var x2:Number = width * a;
+ var y2:Number = width * b;
+
+ // transform point (0, height)
+ var x3:Number = height * c;
+ var y3:Number = height * d;
+
+ // transform point (width, height)
+ var x4:Number = x2 + x3;
+ var y4:Number = y2 + y3;
+
+ var minX:Number = Math.min(Math.min(x1, x2), Math.min(x3, x4));
+ var maxX:Number = Math.max(Math.max(x1, x2), Math.max(x3, x4));
+ var minY:Number = Math.min(Math.min(y1, y2), Math.min(y3, y4));
+ var maxY:Number = Math.max(Math.max(y1, y2), Math.max(y3, y4));
+
+ staticPoint.x = maxX - minX;
+ staticPoint.y = maxY - minY;
+
+ if (topLeft)
+ {
+ const tx:Number = matrix.tx;
+ const ty:Number = matrix.ty;
+ const x:Number = topLeft.x;
+ const y:Number = topLeft.y;
+
+ topLeft.x = minX + a * x + b * y + tx;
+ topLeft.y = minY + c * x + d * y + ty;
+ }
+ return staticPoint;
+ }
+
+ /**
+ * Returns the axis aligned bounding box bounds transformed
+ * with matrix and then projected with projection.
+ *
+ * @param bounds The bounds, in child coordinates, to be transformed and projected.
+ * @param matrix The transformation matrix. Note that the method will clobber the + * original matrix values.
+ * @param projection The projection. + * @return Returns thebounds parameter that has been updated with the
+ * transformed and projected bounds.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function projectBounds(bounds:Rectangle,
+ matrix:Matrix3D,
+ projection:PerspectiveProjection):Rectangle
+ {
+ // Setup the matrix
+ var centerX:Number = projection.projectionCenter.x;
+ var centerY:Number = projection.projectionCenter.y;
+ matrix.appendTranslation(-centerX, -centerY, projection.focalLength);
+ matrix.append(projection.toMatrix3D());
+
+ // Project the corner points
+ var pt1:Vector3D = new Vector3D(bounds.left, bounds.top, 0);
+ var pt2:Vector3D = new Vector3D(bounds.right, bounds.top, 0)
+ var pt3:Vector3D = new Vector3D(bounds.left, bounds.bottom, 0);
+ var pt4:Vector3D = new Vector3D(bounds.right, bounds.bottom, 0);
+ pt1 = Utils3D.projectVector(matrix, pt1);
+ pt2 = Utils3D.projectVector(matrix, pt2);
+ pt3 = Utils3D.projectVector(matrix, pt3);
+ pt4 = Utils3D.projectVector(matrix, pt4);
+
+ // Find the bounding box in 2D
+ var maxX:Number = Math.max(Math.max(pt1.x, pt2.x), Math.max(pt3.x, pt4.x));
+ var minX:Number = Math.min(Math.min(pt1.x, pt2.x), Math.min(pt3.x, pt4.x));
+ var maxY:Number = Math.max(Math.max(pt1.y, pt2.y), Math.max(pt3.y, pt4.y));
+ var minY:Number = Math.min(Math.min(pt1.y, pt2.y), Math.min(pt3.y, pt4.y));
+
+ // Add back the projection center
+ bounds.x = minX + centerX;
+ bounds.y = minY + centerY;
+ bounds.width = maxX - minX;
+ bounds.height = maxY - minY;
+ return bounds;
+ }
+
+ /**
+ * @param matrix
+ * @return Returns true when pt == matrix.DeltaTransformPoint(pt)
+ * for any pt:Point (matrix is identity matrix,
+ * when disregarding the translation part).
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isDeltaIdentity(matrix:Matrix):Boolean
+ {
+ return (matrix.a == 1 && matrix.d == 1 &&
+ matrix.b == 0 && matrix.c == 0);
+ }
+
+ /**
+ * fitBounds Calculates a size (x,y) for a bounding box (0,0,x,y)
+ * such that the bounding box transformed with matrix will fit
+ * into (0,0,width,height).
+ *
+ * @param width This is the width of the bounding box that calculated size
+ * needs to fit in.
+ *
+ * @param height This is the height of the bounding box that the calculated
+ * size needs to fit in.
+ *
+ * @param matrix This defines the transformations that the function will take
+ * into account when calculating the size. The bounding box (0,0,x,y) of the
+ * calculated size (x,y) transformed with matrix will fit in the
+ * specified width and height.
+ *
+ * @param explicitWidth Explicit width for the calculated size. The function
+ * will first try to find a solution using this width.
+ *
+ * @param explicitHeight Preferred height for the calculated size. The function
+ * will first try to find a solution using this height.
+ *
+ * @param preferredWidth Preferred width for the calculated size. If possible
+ * the function will set the calculated size width to this value.
+ *
+ * @param preferredHeight Preferred height for the calculated size. If possible
+ * the function will set the calculated size height to this value.
+ *
+ * @param minWidth The minimum allowed value for the calculated size width.
+ *
+ * @param minHeight The minimum allowed value for the calculated size height.
+ *
+ * @param maxWidth The maximum allowed value for the calculated size width.
+ *
+ * @param maxHeight The maximum allowed value for the calculated size height.
+ *
+ * @return Returns the size (x,y) such that the bounding box (0,0,x,y) will
+ * fit into (0,0,width,height) after transformation with matrix.
+ * Returns null if there is no possible solution.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function fitBounds(width:Number, height:Number, matrix:Matrix,
+ explicitWidth:Number, explicitHeight:Number,
+ preferredWidth:Number, preferredHeight:Number,
+ minWidth:Number, minHeight:Number,
+ maxWidth:Number, maxHeight:Number):Point
+ {
+ if (isNaN(width) && isNaN(height))
+ return new Point(preferredWidth, preferredHeight);
+
+ // Allow for precision errors by including tolerance for certain values.
+ const newMinWidth:Number = (minWidth < MIN_MAX_TOLERANCE) ? 0 : minWidth - MIN_MAX_TOLERANCE;
+ const newMinHeight:Number = (minHeight < MIN_MAX_TOLERANCE) ? 0 : minHeight - MIN_MAX_TOLERANCE;
+ const newMaxWidth:Number = maxWidth + MIN_MAX_TOLERANCE;
+ const newMaxHeight:Number = maxHeight + MIN_MAX_TOLERANCE;
+
+ var actualSize:Point;
+
+ if (!isNaN(width) && !isNaN(height))
+ {
+ actualSize = calcUBoundsToFitTBounds(width, height, matrix,
+ newMinWidth, newMinHeight,
+ newMaxWidth, newMaxHeight);
+
+ // If we couldn't fit in both dimensions, try to fit only one and
+ // don't stick out of the other
+ if (!actualSize)
+ {
+ var actualSize1:Point;
+ actualSize1 = fitTBoundsWidth(width, matrix,
+ explicitWidth, explicitHeight,
+ preferredWidth, preferredHeight,
+ newMinWidth, newMinHeight,
+ newMaxWidth, newMaxHeight);
+
+ // If we fit the width, but not the height.
+ if (actualSize1)
+ {
+ var fitHeight:Number = transformSize(actualSize1.x, actualSize1.y, matrix).y;
+ if (fitHeight - SOLUTION_TOLERANCE > height)
+ actualSize1 = null;
+ }
+
+ var actualSize2:Point
+ actualSize2 = fitTBoundsHeight(height, matrix,
+ explicitWidth, explicitHeight,
+ preferredWidth, preferredHeight,
+ newMinWidth, newMinHeight,
+ newMaxWidth, newMaxHeight);
+
+ // If we fit the height, but not the width
+ if (actualSize2)
+ {
+ var fitWidth:Number = transformSize(actualSize2.x, actualSize2.y, matrix).x;
+ if (fitWidth - SOLUTION_TOLERANCE > width)
+ actualSize2 = null;
+ }
+
+ if (actualSize1 && actualSize2)
+ {
+ // Pick a solution
+ actualSize = ((actualSize1.x * actualSize1.y) > (actualSize2.x * actualSize2.y)) ? actualSize1 : actualSize2;
+ }
+ else if (actualSize1)
+ {
+ actualSize = actualSize1;
+ }
+ else
+ {
+ actualSize = actualSize2;
+ }
+ }
+ return actualSize;
+ }
+ else if (!isNaN(width))
+ {
+ return fitTBoundsWidth(width, matrix,
+ explicitWidth, explicitHeight,
+ preferredWidth, preferredHeight,
+ newMinWidth, newMinHeight,
+ newMaxWidth, newMaxHeight);
+ }
+ else
+ {
+ return fitTBoundsHeight(height, matrix,
+ explicitWidth, explicitHeight,
+ preferredWidth, preferredHeight,
+ newMinWidth, newMinHeight,
+ newMaxWidth, newMaxHeight);
+ }
+ }
+
+ /**
+ * @private
+ *
+ * fitTBoundsWidth Calculates a size (x,y) for a bounding box (0,0,x,y)
+ * such that the bounding box transformed with matrix will fit
+ * into the specified width.
+ *
+ * @param width This is the width of the bounding box that calculated size
+ * needs to fit in.
+ *
+ * @param matrix This defines the transformations that the function will take
+ * into account when calculating the size. The bounding box (0,0,x,y) of the
+ * calculated size (x,y) transformed with matrix will fit in the
+ * specified width and height.
+ *
+ * @param explicitWidth Explicit width for the calculated size. The function
+ * will first try to find a solution using this width.
+ *
+ * @param explicitHeight Preferred height for the calculated size. The function
+ * will first try to find a solution using this height.
+ *
+ * @param preferredWidth Preferred width for the calculated size. If possible
+ * the function will set the calculated size width to this value.
+ *
+ * @param preferredHeight Preferred height for the calculated size. If possible
+ * the function will set the calculated size height to this value.
+ *
+ * @param minWidth The minimum allowed value for the calculated size width.
+ *
+ * @param minHeight The minimum allowed value for the calculated size height.
+ *
+ * @param maxWidth The maximum allowed value for the calculated size width.
+ *
+ * @param maxHeight The maximum allowed value for the calculated size height.
+ *
+ * @return Returns the size (x,y) such that the bounding box (0,0,x,y) will
+ * fit into (0,0,width,height) after transformation with matrix.
+ * Returns null if there is no possible solution.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private static function fitTBoundsWidth(width:Number, matrix:Matrix,
+ explicitWidth:Number, explicitHeight:Number,
+ preferredWidth:Number, preferredHeight:Number,
+ minWidth:Number, minHeight:Number,
+ maxWidth:Number, maxHeight:Number):Point
+ {
+ var actualSize:Point;
+
+ // cases 1 and 2: only explicit width or explicit height is specified,
+ // so we try to find a solution with that hard constraint.
+ if (!isNaN(explicitWidth) && isNaN(explicitHeight))
+ {
+ actualSize = calcUBoundsToFitTBoundsWidth(width, matrix,
+ explicitWidth, preferredHeight,
+ explicitWidth, minHeight,
+ explicitWidth, maxHeight);
+
+ if (actualSize)
+ return actualSize;
+ }
+ else if (isNaN(explicitWidth) && !isNaN(explicitHeight))
+ {
+ actualSize = calcUBoundsToFitTBoundsWidth(width, matrix,
+ preferredWidth, explicitHeight,
+ minWidth, explicitHeight,
+ maxWidth, explicitHeight);
+ if (actualSize)
+ return actualSize;
+ }
+
+ // case 3: default case. When explicitWidth, explicitHeight are both set
+ // or not set, we use the preferred size since calcUBoundsToFitTBoundsWidth
+ // will just pick one.
+ actualSize = calcUBoundsToFitTBoundsWidth(width, matrix,
+ preferredWidth, preferredHeight,
+ minWidth, minHeight,
+ maxWidth, maxHeight);
+
+ return actualSize;
+ }
+
+ /**
+ * @private
+ *
+ * fitTBoundsWidth Calculates a size (x,y) for a bounding box (0,0,x,y)
+ * such that the bounding box transformed with matrix will fit
+ * into the specified height.
+ *
+ * @param height This is the height of the bounding box that the calculated
+ * size needs to fit in.
+ *
+ * @param matrix This defines the transformations that the function will take
+ * into account when calculating the size. The bounding box (0,0,x,y) of the
+ * calculated size (x,y) transformed with matrix will fit in the
+ * specified width and height.
+ *
+ * @param explicitWidth Explicit width for the calculated size. The function
+ * will first try to find a solution using this width.
+ *
+ * @param explicitHeight Preferred height for the calculated size. The function
+ * will first try to find a solution using this height.
+ *
+ * @param preferredWidth Preferred width for the calculated size. If possible
+ * the function will set the calculated size width to this value.
+ *
+ * @param preferredHeight Preferred height for the calculated size. If possible
+ * the function will set the calculated size height to this value.
+ *
+ * @param minWidth The minimum allowed value for the calculated size width.
+ *
+ * @param minHeight The minimum allowed value for the calculated size height.
+ *
+ * @param maxWidth The maximum allowed value for the calculated size width.
+ *
+ * @param maxHeight The maximum allowed value for the calculated size height.
+ *
+ * @return Returns the size (x,y) such that the bounding box (0,0,x,y) will
+ * fit into (0,0,width,height) after transformation with matrix.
+ * Returns null if there is no possible solution.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private static function fitTBoundsHeight(height:Number, matrix:Matrix,
+ explicitWidth:Number, explicitHeight:Number,
+ preferredWidth:Number, preferredHeight:Number,
+ minWidth:Number, minHeight:Number,
+ maxWidth:Number, maxHeight:Number):Point
+ {
+ var actualSize:Point;
+
+ // cases 1 and 2: only explicit width or explicit height is specified,
+ // so we try to find a solution with that hard constraint.
+ if (!isNaN(explicitWidth) && isNaN(explicitHeight))
+ {
+ actualSize = calcUBoundsToFitTBoundsHeight(height, matrix,
+ explicitWidth, preferredHeight,
+ explicitWidth, minHeight,
+ explicitWidth, maxHeight);
+
+ if (actualSize)
+ return actualSize;
+ }
+ else if (isNaN(explicitWidth) && !isNaN(explicitHeight))
+ {
+ actualSize = calcUBoundsToFitTBoundsHeight(height, matrix,
+ preferredWidth, explicitHeight,
+ minWidth, explicitHeight,
+ maxWidth, explicitHeight);
+ if (actualSize)
+ return actualSize;
+ }
+
+ // case 3: default case. When explicitWidth, explicitHeight are both set
+ // or not set, we use the preferred size since calcUBoundsToFitTBoundsWidth
+ // will just pick one.
+ actualSize = calcUBoundsToFitTBoundsHeight(height, matrix,
+ preferredWidth, preferredHeight,
+ minWidth, minHeight,
+ maxWidth, maxHeight);
+
+ return actualSize;
+ }
+
+ /**
+ * Calculates (x,y) such that the bounding box (0,0,x,y) transformed
+ * with matrix will have bounding box with
+ * height equal to h.
+ * x and y are restricted by minX, maxX and
+ * minY, maxY.
+ *
+ * If possible x will be set to preferredX or
+ * y will be set to preferredY.
+ *
+ * When there are multiple solutions, the function picks the one that
+ * minimizes the bounding box area of transformed (0,0,x,y).
+ *
+ * The functon assumes minX >= 0 and minY >= 0
+ * (solution components x and y are non-negative).
+ *
+ * @return Returns Point(x,y) or null if no solution exists.
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ static public function calcUBoundsToFitTBoundsHeight(h:Number,
+ matrix:Matrix,
+ preferredX:Number,
+ preferredY:Number,
+ minX:Number,
+ minY:Number,
+ maxX:Number,
+ maxY:Number):Point
+ {
+ // Untransformed bounds size is (x,y). The corners of the untransformed
+ // bounding box are p1(0,0) p2(x,0) p3(0,y) p4(x,y).
+ // Matrix is | a c tx |
+ // | b d ty |
+ //
+ // After transfomation with the matrix those four points are:
+ // t1 = (0, 0) = matrix.deltaTransformPoint(p1)
+ // t2 = (ax, bx) = matrix.deltaTransformPoint(p2)
+ // t3 = (cy, dy) = matrix.deltaTransformPoint(p3)
+ // t4 = (ax + cy, cx + dy) = matrix.deltaTransformPoint(p4)
+ //
+ // The transformed bounds bounding box dimensions are (w,h):
+ // (1) w = max( t1.x, t2.x, t3.x, t4.x ) - min( t1.x, t2.x, t3.x, t4.x)
+ // (2) h = max( t1.y, t2.y, t3.y, t4.y ) - min( t1.y, t2.y, t3.y, t4.y)
+ //
+ // Looking at all the possible cases for min and max functions above,
+ // we can construct and solve simple linear systems for x and y.
+ // For example in the case of
+ // t1.x <= t2.x <= t3.x <= t4.x
+ // our first equation is
+ // (1) w = t4.x - t1.x <==> w = ax + cy
+ //
+ // To minimize the cases we're looking at we can take advantage of
+ // the limits we have: x >= 0, y >= 0;
+ // Taking into account these limits we deduce that:
+ // a*c >= 0 gives us (1) w = abs( t4.x - t1.x ) = abs( ax + cy )
+ // a*c < 0 gives us (1) w = abs( t2.x - t3.x ) = abs( ax - cy )
+ // b*d >= 0 gives us (2) h = abs( t4.y - t1.y ) = abs( bx + dy )
+ // b*d < 0 gives us (2) h = abs( t2.y - t3.y ) = abs( bx - dy )
+ //
+ // If we do a substitution such that
+ // c1 = a*c >= 0 ? c : -c
+ // d1 = b*d >= 0 ? d : -d
+ // we get the following linear system:
+ // (1) w = abs( ax + c1y )
+ // (2) h = abs( bx + d1y )
+ //
+ // Since we're matching height we only care about (2)
+
+ var b:Number = matrix.b;
+ var d:Number = matrix.d;
+
+ // If components are very close to zero, zero them out to handle the special cases
+ if (-1.0e-9 < b && b < +1.0e-9)
+ b = 0;
+ if (-1.0e-9 < d && d < +1.0e-9)
+ d = 0;
+
+ if (b == 0 && d == 0)
+ return null; // No solution
+
+ // Handle special cases first
+ if (b == 0 && d == 0)
+ return null; // No solution
+
+ if (b == 0)
+ return new Point( preferredX, h / Math.abs(d) );
+ else if (d == 0)
+ return new Point( h / Math.abs(b), preferredY );
+
+ const d1:Number = (b*d >= 0) ? d : -d;
+ // Now we have the following linear sytesm:
+ // (1) x = preferredX or y = preferredY
+ // (2) h = abs( bx + d1y )
+
+ var s:Point;
+ var x:Number;
+ var y:Number;
+
+ if (d1 != 0 && preferredX > 0)
+ {
+ const invD1:Number = 1 / d1;
+ preferredX = Math.max(minX, Math.min(maxX, preferredX));
+ x = preferredX;
+
+ // Case1:
+ // bx + d1y >= 0
+ // x = preferredX
+ y = (h - b * x) * invD1;
+ if (minY <= y && y <= maxY &&
+ b * x + d1 * y >= 0 ) // Satisfy Case1
+ {
+ s = new Point(x, y);
+ }
+
+ // Case2:
+ // bx + d1y < 0
+ // x = preferredX
+ y = (-h - b * x) * invD1;
+ if (minY <= y && y <= maxY &&
+ b * x + d1 * y < 0 ) // Satisfy Case2
+ {
+ // If there is no solution, or the new solution yields smaller value, pick the new solution.
+ if (!s || transformSize(s.x, s.y, matrix).x > transformSize(x, y, matrix).x)
+ s = new Point(x, y);
+ }
+ }
+
+ if (b != 0 && preferredY > 0)
+ {
+ const invB:Number = 1 / b;
+ preferredY = Math.max(minY, Math.min(maxY, preferredY));
+ y = preferredY;
+
+ // Case3:
+ // bx + d1y >= 0
+ // y = preferredY
+ x = ( h - d1 * y ) * invB;
+ if (minX <= x && x <= maxX &&
+ b * x + d1 * y >= 0) // Satisfy Case3
+ {
+ // If there is no solution, or the new solution yields smaller value, pick the new solution.
+ if (!s || transformSize(s.x, s.y, matrix).x > transformSize(x, y, matrix).x)
+ s = new Point(x, y);
+ }
+
+ // Case4:
+ // bx + d1y < 0
+ // y = preferredY
+ x = ( -h - d1 * y ) * invB;
+ if (minX <= x && x <= maxX &&
+ b * x + d1 * y < 0) // Satisfy Case4
+ {
+ // If there is no solution, or the new solution yields smaller value, pick the new solution.
+ if (!s || transformSize(s.x, s.y, matrix).x > transformSize(x, y, matrix).x)
+ s = new Point(x, y);
+ }
+ }
+
+ // If there's already a solution that matches preferred dimention, return
+ if (s)
+ return s;
+
+ // Find a solution that matches the width and minimizes the height:
+ const a:Number = matrix.a;
+ const c:Number = matrix.c;
+ const c1:Number = ( a*c >= 0 ) ? c : -c;
+ return solveEquation(b, d1, h, minX, minY, maxX, maxY, a, c1);
+ }
+
+ /**
+ * Calculates (x,y) such that the bounding box (0,0,x,y) transformed
+ * with matrix will have bounding box with
+ * width equal to w.
+ * x and y are restricted by minX, maxX and
+ * minY, maxY.
+ *
+ * If possible x will be set to preferredX or
+ * y will be set to preferredY.
+ *
+ * When there are multiple solutions, the function picks the one that
+ * minimizes the bounding box area of transformed (0,0,x,y).
+ *
+ * The functon assumes minX >= 0 and minY >= 0
+ * (solution components x and y are non-negative).
+ *
+ * @return Returns Point(x,y) or null if no solution exists.
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ static public function calcUBoundsToFitTBoundsWidth(w:Number,
+ matrix:Matrix,
+ preferredX:Number,
+ preferredY:Number,
+ minX:Number,
+ minY:Number,
+ maxX:Number,
+ maxY:Number):Point
+ {
+ // Untransformed bounds size is (x,y). The corners of the untransformed
+ // bounding box are p1(0,0) p2(x,0) p3(0,y) p4(x,y).
+ // Matrix is | a c tx |
+ // | b d ty |
+ //
+ // After transfomation with the matrix those four points are:
+ // t1 = (0, 0) = matrix.deltaTransformPoint(p1)
+ // t2 = (ax, bx) = matrix.deltaTransformPoint(p2)
+ // t3 = (cy, dy) = matrix.deltaTransformPoint(p3)
+ // t4 = (ax + cy, cx + dy) = matrix.deltaTransformPoint(p4)
+ //
+ // The transformed bounds bounding box dimensions are (w,h):
+ // (1) w = max( t1.x, t2.x, t3.x, t4.x ) - min( t1.x, t2.x, t3.x, t4.x)
+ // (2) h = max( t1.y, t2.y, t3.y, t4.y ) - min( t1.y, t2.y, t3.y, t4.y)
+ //
+ // Looking at all the possible cases for min and max functions above,
+ // we can construct and solve simple linear systems for x and y.
+ // For example in the case of
+ // t1.x <= t2.x <= t3.x <= t4.x
+ // our first equation is
+ // (1) w = t4.x - t1.x <==> w = ax + cy
+ //
+ // To minimize the cases we're looking at we can take advantage of
+ // the limits we have: x >= 0, y >= 0;
+ // Taking into account these limits we deduce that:
+ // a*c >= 0 gives us (1) w = abs( t4.x - t1.x ) = abs( ax + cy )
+ // a*c < 0 gives us (1) w = abs( t2.x - t3.x ) = abs( ax - cy )
+ // b*d >= 0 gives us (2) h = abs( t4.y - t1.y ) = abs( bx + dy )
+ // b*d < 0 gives us (2) h = abs( t2.y - t3.y ) = abs( bx - dy )
+ //
+ // If we do a substitution such that
+ // c1 = a*c >= 0 ? c : -c
+ // d1 = b*d >= 0 ? d : -d
+ // we get the following linear system:
+ // (1) w = abs( ax + c1y )
+ // (2) h = abs( bx + d1y )
+ //
+ // Since we're matching width we only care about (1)
+
+ var a:Number = matrix.a;
+ var c:Number = matrix.c;
+
+ // If components are very close to zero, zero them out to handle the special cases
+ if (-1.0e-9 < a && a < +1.0e-9)
+ a = 0;
+ if (-1.0e-9 < c && c < +1.0e-9)
+ c = 0;
+
+ // Handle special cases first
+ if (a == 0 && c == 0)
+ return null; // No solution
+
+ if (a == 0)
+ return new Point( preferredX, w / Math.abs(c) );
+ else if (c == 0)
+ return new Point( w / Math.abs(a), preferredY );
+
+ const c1:Number = ( a*c >= 0 ) ? c : -c;
+ // Now we have the following linear sytesm:
+ // (1) w = abs( ax + c1y )
+ // (2) x = preferredX or y = preferredY
+
+ var s:Point;
+ var x:Number;
+ var y:Number;
+
+ if (c1 != 0 && preferredX > 0)
+ {
+ const invC1:Number = 1 / c1;
+ preferredX = Math.max(minX, Math.min(maxX, preferredX));
+ x = preferredX;
+
+ // Case1:
+ // a * x + c1 * y >= 0
+ // x = preferredX
+ y = (w - a * x) * invC1;
+ if (minY <= y && y <= maxY &&
+ a * x + c1 * y >= 0 ) // Satisfy Case1
+ {
+ s = new Point(x, y);
+ }
+
+ // Case2:
+ // a * x + c1 * y < 0
+ // x = preferredX
+ y = (-w - a * x) * invC1;
+ if (minY <= y && y <= maxY &&
+ a * x + c1 * y < 0 ) // Satisfy Case2
+ {
+ // If there is no solution, or the new solution yields smaller value, pick the new solution.
+ if (!s || transformSize(s.x, s.y, matrix).y > transformSize(x, y, matrix).y)
+ s = new Point(x, y);
+ }
+ }
+
+ if (a != 0 && preferredY > 0)
+ {
+ const invA:Number = 1 / a;
+ preferredY = Math.max(minY, Math.min(maxY, preferredY));
+ y = preferredY;
+
+ // Case3:
+ // a * x + c1 * y >= 0
+ // y = preferredY
+ x = (w - c1 * y ) * invA;
+ if (minX <= x && x <= maxX &&
+ a * x + c1 * y >= 0) // Satisfy Case3
+ {
+ // If there is no solution, or the new solution yields smaller value, pick the new solution.
+ if (!s || transformSize(s.x, s.y, matrix).y > transformSize(x, y, matrix).y)
+ s = new Point(x, y);
+ }
+
+ // Case4:
+ // a * x + c1 * y < 0
+ // y = preferredY
+ x = (-w - c1 * y ) * invA;
+ if (minX <= x && x <= maxX &&
+ a * x + c1 * y < 0) // Satisfy Case4
+ {
+ // If there is no solution, or the new solution yields smaller value, pick the new solution.
+ if (!s || transformSize(s.x, s.y, matrix).y > transformSize(x, y, matrix).y)
+ s = new Point(x, y);
+ }
+ }
+
+ // If there's already a solution that matches preferred dimention, return
+ if (s)
+ return s;
+
+ // Find a solution that matches the width and minimizes the height:
+ const b:Number = matrix.b;
+ const d:Number = matrix.d;
+ const d1:Number = (b*d >= 0) ? d : -d;
+ return solveEquation(a, c1, w, minX, minY, maxX, maxY, b, d1);
+ }
+
+ /**
+ * Finds a solution (x,y) for the equation abs(a*x + c*y) = w such that
+ * abs(b*x +d*y) is minimized.
+ * If there is infinite number of solutions, x and y are picked to be
+ * as close as possible.
+ *
+ * Doesn't handle cases where a or c are zero.
+ *
+ * @return Returns Point(x,y)
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ static private function solveEquation(a:Number,
+ c:Number,
+ w:Number,
+ minX:Number,
+ minY:Number,
+ maxX:Number,
+ maxY:Number,
+ b:Number,
+ d:Number):Point
+ {
+ if (a == 0 || c == 0)
+ return null; // x and y are not co-dependent
+
+ // (1) w = abs( ax + cy )
+ // Find the range of solutsion for y and pick:
+ var x:Number;
+ var y:Number;
+ var s:Point;
+
+ // Case1: ax + cy >= 0, from (1) above we get:
+ // (1) x = (w - cy) / a
+ //
+ // Lets find the possible range of values for y:
+ // We know that
+ // (3) minX <= x <= maxX
+ //
+ // Substitute x with (w - cy)/a in (3):
+ // (3) minX - w/a <= -cy/a <= maxX - w/a
+ // (3) min( A, B ) <= y <= max( A, B ), where
+ // A = (minX - w/a) * (-a/c)
+ // B = (maxX - w/a) * (-a/c)
+
+ var A:Number = (w - minX * a) / c;
+ var B:Number = (w - maxX * a) / c;
+ var rangeMinY:Number = Math.max(minY, Math.min(A, B));
+ var rangeMaxY:Number = Math.min(maxY, Math.max(A, B));
+ const det:Number = (b * c - a * d);
+
+ // We have a possible solution for Case1 if the range for y is valid
+ if (rangeMinY <= rangeMaxY)
+ {
+ // Now that we have a valid range for y, we need to pick a value within
+ // that range.
+ //
+ // We calculate the value based on a custom condition.
+ //
+ // The custom condition that we use could be anything that defines
+ // another equation for x and y. Some examples are:
+ // "make x and y as close as possible": y = w / ( a + c );
+ // "minimize abs(bx + dy)": y = b * w / det
+ // "preserve aspect ratio": y = w / ( a * preferredX / preferredY + c );
+ if (Math.abs(det) < 1.0e-9)
+ {
+ // There is infinite number of solutions, lets pick x == y
+ y = w / ( a + c );
+ }
+ else
+ {
+ // Minimize abs(bx + dy) - we need to solve:
+ // abs( b * ( w - c * y ) / a + d * y ) = 0
+ // which gives us:
+ y = b * w / det;
+ }
+
+ // Now that we have the y value calculated from the custom condition,
+ // we clamp with the range. This gives us a solution with
+ // values as close as possible to satisfy our custom condition when
+ // the condition is a linear function of x and y (in our case it is).
+ y = Math.max(rangeMinY, Math.min(y, rangeMaxY));
+
+ x = (w - c * y) / a;
+ return new Point(x, y);
+ }
+
+ // Case2: ax + cy < 0, from (1) above we get:
+ // (1) x = (-w - cy) / a
+ //
+ // Lets find the possible range of values for y:
+ // We know that
+ // (3) minX <= x <= maxX
+ //
+ // Substitute x with (-w - cy)/a in (3):
+ // (3) minX + w/a <= -cy/a <= maxX + w/a
+ // (3) min( A, B ) <= y <= max( A, B ), where
+ // A = (minX + w/a) * (-a/c)
+ // B = (maxX + w/a) * (-a/c)
+
+ A = -(minX * a + w) / c;
+ B = -(maxX * a + w) / c;
+ rangeMinY = Math.max(minY, Math.min(A, B));
+ rangeMaxY = Math.min(maxY, Math.max(A, B));
+
+ // We have a possible solution for Case2 if the range for y is valid
+ if (rangeMinY <= rangeMaxY)
+ {
+ // Now that we have a valid range for y, we need to pick a value within
+ // that range.
+ //
+ // We calculate the value based on a custom condition.
+ //
+ // The custom condition that we use could be anything that defines
+ // another equation for x and y. Some examples are:
+ // "make x and y as close as possible": y = -w / ( a + c );
+ // "minimize abs(bx + dy)": y = -b * w / det
+ // "preserve aspect ratio": y = w / ( a * preferredX / preferredY + c );
+ if (Math.abs(det) < 1.0e-9)
+ {
+ // There is infinite number of solutions, lets pick x == y
+ y = -w / ( a + c );
+ }
+ else
+ {
+ // Minimize abs(bx + dy) - we need to solve:
+ // abs( b * ( -w - c * y ) / a + d * y ) = 0
+ // which gives us:
+ y = -b * w / det;
+ }
+
+ // Now that we have the y value calculated from the custom condition,
+ // we clamp with the range. This gives us a solution with
+ // values as close as possible to satisfy our custom condition when
+ // the condition is a linear function of x and y (in our case it is).
+ y = Math.max(rangeMinY, Math.min(y, rangeMaxY));
+ x = (-w - c * y) / a;
+ return new Point(x, y);
+
+ }
+ return null; // No solution
+ }
+
+ /**
+ * Calculates (x,y) such that the bounding box (0,0,x,y) transformed
+ * with matrix will have bounding box (0,0,w,h).
+ * x and y are restricted by minX, maxX and
+ * minY, maxY.
+ *
+ * When there is infinite number of solutions, the function will
+ * calculate x and y to be as close as possible.
+ *
+ * The functon assumes minX >= 0 and minY >= 0
+ * (solution components x and y are non-negative).
+ *
+ * @return Point(x,y) or null if no solution exists.
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ static public function calcUBoundsToFitTBounds(w:Number,
+ h:Number,
+ matrix:Matrix,
+ minX:Number,
+ minY:Number,
+ maxX:Number,
+ maxY:Number):Point
+ {
+ // Untransformed bounds size is (x,y). The corners of the untransformed
+ // bounding box are p1(0,0) p2(x,0) p3(0,y) p4(x,y).
+ // Matrix is | a c tx |
+ // | b d ty |
+ //
+ // After transfomation with the matrix those four points are:
+ // t1 = (0, 0) = matrix.deltaTransformPoint(p1)
+ // t2 = (ax, bx) = matrix.deltaTransformPoint(p2)
+ // t3 = (cy, dy) = matrix.deltaTransformPoint(p3)
+ // t4 = (ax + cy, cx + dy) = matrix.deltaTransformPoint(p4)
+ //
+ // The transformed bounds bounding box dimensions are (w,h):
+ // (1) w = max( t1.x, t2.x, t3.x, t4.x ) - min( t1.x, t2.x, t3.x, t4.x)
+ // (2) h = max( t1.y, t2.y, t3.y, t4.y ) - min( t1.y, t2.y, t3.y, t4.y)
+ //
+ // Looking at all the possible cases for min and max functions above,
+ // we can construct and solve simple linear systems for x and y.
+ // For example in the case of
+ // t1.x <= t2.x <= t3.x <= t4.x
+ // our first equation is
+ // (1) w = t4.x - t1.x <==> w = ax + cy
+ //
+ // To minimize the cases we're looking at we can take advantage of
+ // the limits we have: x >= 0, y >= 0;
+ // Taking into account these limits we deduce that:
+ // a*c >= 0 gives us (1) w = abs( t4.x - t1.x ) = abs( ax + cy )
+ // a*c < 0 gives us (1) w = abs( t2.x - t3.x ) = abs( ax - cy )
+ // b*d >= 0 gives us (2) h = abs( t4.y - t1.y ) = abs( bx + dy )
+ // b*d < 0 gives us (2) h = abs( t2.y - t3.y ) = abs( bx - dy )
+ //
+ // If we do a substitution such that
+ // c1 = a*c >= 0 ? c : -c
+ // d1 = b*d >= 0 ? d : -d
+ // we get the following linear system:
+ // (1) w = abs( ax + c1y )
+ // (2) h = abs( bx + d1y )
+ //
+
+ var a:Number = matrix.a;
+ var b:Number = matrix.b;
+ var c:Number = matrix.c;
+ var d:Number = matrix.d;
+
+ // If components are very close to zero, zero them out to handle the special cases
+ if (-1.0e-9 < a && a < +1.0e-9)
+ a = 0;
+ if (-1.0e-9 < b && b < +1.0e-9)
+ b = 0;
+ if (-1.0e-9 < c && c < +1.0e-9)
+ c = 0;
+ if (-1.0e-9 < d && d < +1.0e-9)
+ d = 0;
+
+ // Handle special cases.
+ if (b == 0 && c == 0)
+ {
+ // No solution in the following cases since the matrix collapses
+ // all points into a line.
+ if (a == 0 || d == 0)
+ return null;
+
+ // (1) w = abs( ax + cy ) <=> w = abs( ax ) <=> w = abs(a)x
+ // (2) h = abs( bx + dy ) <=> h = abs( dy ) <=> h = abs(d)y
+ return new Point(w / Math.abs(a), h / Math.abs(d));
+ }
+
+ if (a == 0 && d == 0)
+ {
+ // No solution in the following cases since the matrix collapses
+ // all points into a line.
+ if (b == 0 || c == 0)
+ return null;
+
+ // (1) w = abs( ax + cy ) <=> w = abs( cy ) <=> w = abs(c)y
+ // (2) h = abs( bx + dy ) <=> h = abs( bx ) <=> h = abs(b)x
+ return new Point(h / Math.abs(b), w / Math.abs(c));
+ }
+
+ // Handle general cases.
+ const c1:Number = ( a*c >= 0 ) ? c : -c;
+ const d1:Number = ( b*d >= 0 ) ? d : -d;
+ // we get the following linear system:
+ // (1) w = abs( ax + c1y )
+ // (2) h = abs( bx + d1y )
+
+ // Calculate the determinant of the system
+ const det:Number = a * d1 - b * c1;
+ if (Math.abs(det) < 1.0e-9)
+ {
+ // No solution in these cases since the matrix
+ // collapses all points into a line.
+ if (c1 == 0 || a == 0 || a == -c1)
+ return null;
+
+ if (Math.abs(a * h - b * w) > 1.0e-9)
+ return null; // No solution in this case
+
+ // Determinant is zero, the equations (1) & (2) are equivalent and
+ // we have only one equation:
+ // (1) w = abs( ax + c1y )
+ //
+ // Solve it finding x and y as close as possible:
+ return solveEquation(a, c1, w, minX, minX, maxX, maxY, b, d1);
+ }
+
+ // Pre-multiply w & h by the inverse dteterminant
+ const invDet:Number = 1 / det;
+ w *= invDet;
+ h *= invDet;
+
+ // Case 1:
+ // a * x + c1 * y >= 0
+ // b * x + d1 * y >= 0
+ var s:Point;
+ s = solveSystem(a, c1, b, d1, w, h);
+ if (s &&
+ minX <= s.x && s.x <= maxX && minY <= s.y && s.y <= maxY &&
+ a * s.x + c1 * s.x >= 0 &&
+ b * s.x + d1 * s.y >= 0)
+ return s;
+
+ // Case 2:
+ // a * x + c1 * y >= 0
+ // b * x + d1 * y < 0
+ s = solveSystem( a, c1, b, d1, w, -h);
+ if (s &&
+ minX <= s.x && s.x <= maxX && minY <= s.y && s.y <= maxY &&
+ a * s.x + c1 * s.x >= 0 &&
+ b * s.x + d1 * s.y < 0)
+ return s;
+
+ // Case 3:
+ // a * x + c1 * y < 0
+ // b * x + d1 * y >= 0
+ s = solveSystem( a, c1, b, d1, -w, h);
+ if (s &&
+ minX <= s.x && s.x <= maxX && minY <= s.y && s.y <= maxY &&
+ a * s.x + c1 * s.x < 0 &&
+ b * s.x + d1 * s.y >= 0)
+ return s;
+
+ // Case 4:
+ // a * x + c1 * y < 0
+ // b * x + d1 * y < 0
+ s = solveSystem( a, c1, b, d1, -w, -h);
+ if (s &&
+ minX <= s.x && s.x <= maxX && minY <= s.y && s.y <= maxY &&
+ a * s.x + c1 * s.x < 0 &&
+ b * s.x + d1 * s.y < 0)
+ return s;
+
+ return null; // No solution.
+ }
+
+ /**
+ * Determine if two Matrix instances are equal.
+ *
+ * @return true if the matrices are equal.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isEqual(m1:Matrix, m2:Matrix):Boolean
+ {
+ return ((m1 && m2 &&
+ m1.a == m2.a &&
+ m1.b == m2.b &&
+ m1.c == m2.c &&
+ m1.d == m2.d &&
+ m1.tx == m2.tx &&
+ m1.ty == m2.ty) ||
+ (!m1 && !m2));
+ }
+
+ /**
+ * Determine if two Matrix3D instances are equal.
+ *
+ * @return true if the matrices are equal.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isEqual3D(m1:Matrix3D, m2:Matrix3D):Boolean
+ {
+ if (m1 && m2 && m1.rawData.length == m2.rawData.length)
+ {
+ var r1:Vector.mOverDet must be equal to m / (a*d - b*c)
+ * @param nOverDet mOverDet must be equal to n / (a*d - b*c)
+ *
+ * @return returns Point(x,y)
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ static private function solveSystem(a:Number,
+ c:Number,
+ b:Number,
+ d:Number,
+ mOverDet:Number,
+ nOverDet:Number):Point
+ {
+ return new Point(d * mOverDet - c * nOverDet,
+ a * nOverDet - b * mOverDet);
+ }
+
+ /**
+ * Workaround for player's concatenatedMatrix being wrong in some situations, such
+ * as when there is a filter or a scrollRect somewhere in the object's container
+ * hierarchy. Walk the parent tree manually, calculating the matrix manually.
+ *
+ * @param displayObject Calculate the concatenatedMatrix for this displayObject
+ *
+ * @param topParent When specified, the matrix is computed up to the topParent, + * excluding topParent's concatenated matrix. This is useful when computing a transform + * in order to move an object to a different parent but the object's transform needs + * to be adjusted in order to keep its original position on screen.
+ * + * @return The concatenatedMatrix for the displayObject + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + public static function getConcatenatedMatrix(displayObject:DisplayObject, topParent:DisplayObject):Matrix + { + return getConcatenatedMatrixHelper(displayObject, false, topParent); + } + + /** + * Workaround for player's concatenatedMatrix being wrong in some situations, such + * as when there is a filter or a scrollRect somewhere in the object's container + * hierarchy. Walk the parent tree manually, calculating the matrix manually. + * + * This function differs from getConcatenatedMatrix in that it combines the + * computedMatrix of each ancestor. The computedMatrix includes transform offsets. + * + * @param displayObject Calculate the concatenatedMatrix for this displayObject + * + * @param topParentWhen specified, the matrix is computed up to the topParent, + * excluding topParent's concatenated matrix. This is useful when computing a transform + * in order to move an object to a different parent but the object's transform needs + * to be adjusted in order to keep its original position on screen.
+ * + * @return The concatenatedMatrix for the displayObject + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + public static function getConcatenatedComputedMatrix(displayObject:DisplayObject, topParent:DisplayObject):Matrix + { + return getConcatenatedMatrixHelper(displayObject, true, topParent); + } + + /** + * @private + */ + private static function getConcatenatedMatrixHelper(displayObject:DisplayObject, useComputedMatrix:Boolean, topParent:DisplayObject):Matrix + { + var m:Matrix = new Matrix(); + + // This check should be made once per top-level ApplicationDomain + if (usesMarshalling == null) + { + // Check if marshalling support has been turned on + usesMarshalling = ApplicationDomain.currentDomain.hasDefinition("mx.managers.systemClasses.MarshallingSupport"); + + // If we aren't using marshalling, then we only have one ApplicationDomain and thus one class + // definition for UIComponent + if (!usesMarshalling && ApplicationDomain.currentDomain.hasDefinition("mx.core.UIComponent")) + uiComponentClass = Class(ApplicationDomain.currentDomain.getDefinition("mx.core.UIComponent")); + // same thing for UIMovieClip + if (!usesMarshalling && ApplicationDomain.currentDomain.hasDefinition("mx.flash.UIMovieClip")) + uiMovieClipClass = Class(ApplicationDomain.currentDomain.getDefinition("mx.flash.UIMovieClip")); + } + + // Note, root will be "null" if the displayObject is off the display list. In particular, + // during start-up, before applicationComplete is dispatched, root will be null. + // Note that getConcatenatedMatrixHelper() with topParent == sandboxRoot will still work + // correctly in those cases as we use ".$parent" to walk up the parent chain and during start-up + // $parent will be null for the application before applicationComplete has been dispatched. + + if (fakeDollarParent == null) + fakeDollarParent = new QName(mx_internal, "$parent"); + + if (useComputedMatrix && computedMatrixProperty == null) + computedMatrixProperty = new QName(mx_internal, "computedMatrix"); + + if ($transformProperty == null) + $transformProperty = new QName(mx_internal, "$transform"); + + while (displayObject && displayObject.transform.matrix && displayObject != topParent) + { + var scrollRect:Rectangle = displayObject.scrollRect; + if (scrollRect != null) + m.translate(-scrollRect.x, -scrollRect.y); + + // If we are using marshalling, we can have multiple class definitions of UIComponent + if (usesMarshalling && "moduleFactory" in displayObject) + { + var moduleFactory:Object = displayObject["moduleFactory"]; + // If the module factory has changed, then we are in a different ApplicationDomain + if (moduleFactory && moduleFactory !== lastModuleFactory && "info" in moduleFactory) + { + var appDomain:ApplicationDomain; + + appDomain = moduleFactory["info"]()["currentDomain"]; + // Get the class definition for UIComponent in the current ApplicationDomain + if (appDomain && appDomain.hasDefinition("mx.core.UIComponent")) + uiComponentClass = Class(appDomain.getDefinition("mx.core.UIComponent")); + // same thing for UIMovieClip + if (appDomain && appDomain.hasDefinition("mx.flash.UIMovieClip")) + uiMovieClipClass = Class(appDomain.getDefinition("mx.flash.UIMovieClip")); + + lastModuleFactory = moduleFactory; + } + } + + var isUIComponent:Boolean = uiComponentClass && displayObject is uiComponentClass; + var isUIMovieClip:Boolean = uiMovieClipClass && displayObject is uiMovieClipClass; + + if (useComputedMatrix && isUIComponent) + m.concat(displayObject[computedMatrixProperty]); + else if (isUIMovieClip) + m.concat(displayObject[$transformProperty].matrix); + else + m.concat(displayObject.transform.matrix); + + // Try to access $parent, which is the true display list parent + if (isUIComponent) + displayObject = displayObject[fakeDollarParent] as DisplayObject; + else + displayObject = displayObject.parent as DisplayObject; + } + return m; + } + +} + +} diff --git a/src/mx/utils/NameUtil.as b/src/mx/utils/NameUtil.as new file mode 100644 index 00000000..66ad1536 --- /dev/null +++ b/src/mx/utils/NameUtil.as @@ -0,0 +1,179 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2006 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.utils +{ + +import flash.display.DisplayObject; +import flash.utils.getQualifiedClassName; +//import mx.core.IRepeaterClient; + +/** + * The NameUtil utility class defines static methods for + * creating names for Flex objects. + * You do not create instances of NameUtil; + * instead you call static methods of the class, such as + * theNameUtil.createName() method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class NameUtil
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private static var counter:int = 0;
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Creates a unique name for any Object instance, such as "Button12", by
+ * combining the unqualified class name with an incrementing counter.
+ *
+ * @param object Object requiring a name.
+ *
+ * @return String containing the unique name.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function createUniqueName(object:Object):String
+ {
+ if (!object)
+ return null;
+
+ var name:String = getQualifiedClassName(object);
+
+ // If there is a package name, strip it off.
+ var index:int = name.indexOf("::");
+ if (index != -1)
+ name = name.substr(index + 2);
+
+ // If the class name ends with a digit (which some autogenerated
+ // classes do), then append an underscore before appending
+ // the counter.
+ var charCode:int = name.charCodeAt(name.length - 1);
+ if (charCode >= 48 && charCode <= 57)
+ name += "_";
+
+ return name + counter++;
+ }
+
+ /**
+ * Returns a string, such as
+ * "MyApplication0.addressForm.lastName.TextField17",
+ * for a DisplayObject object that indicates its position in the
+ * hierarchy of DisplayObject objects in an application.
+ *
+ * @param displayObject A DisplayObject object whose hierarchy in the application
+ * is desired.
+ *
+ * @return String containing the position of displayObject
+ * in the hierarchy of DisplayObject objects in an application.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function displayObjectToString(
+ displayObject:DisplayObject):String
+ {
+ var result:String;
+
+ // Start at the specified object and walk up the parent chain
+ // to build up the string to return.
+ try
+ {
+ for (var o:DisplayObject = displayObject;
+ o != null;
+ o = o.parent)
+ {
+ // If this object is in the display tree,
+ // stop after we've prepended the topmost Application instance.
+ if (o.parent && o.stage && o.parent == o.stage)
+ break;
+
+ // Prefer id over name if specified.
+ var s:String = "id" in o && o["id"] ? o["id"] : o.name;
+ /*
+ if (o is IRepeaterClient)
+ {
+ var indices:Array = IRepeaterClient(o).instanceIndices;
+ if (indices)
+ s += "[" + indices.join("][") + "]";
+ }
+ */
+ result = result == null ? s : s + "." + result;
+ }
+ }
+ catch (e:SecurityError)
+ {
+ // Ignore error and continue with what we have.
+ // We may not have access to our parent if we are loaded into a sandbox.
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the name of the specified object's class,
+ * such as "Button"
+ *
+ * This string does not include the package name.
+ * If you need the package name as well, call the
+ * getQualifiedClassName() method in the flash.utils package.
+ * It will return a string such as "mx.controls::Button".
StringUtil.substitute() method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class StringUtil
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Removes all whitespace characters from the beginning and end
+ * of the specified string.
+ *
+ * @param str The String whose whitespace should be trimmed.
+ *
+ * @return Updated String where whitespace was removed from the
+ * beginning and end.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function trim(str:String):String
+ {
+ if (str == null) return '';
+
+ var startIndex:int = 0;
+ while (isWhitespace(str.charAt(startIndex)))
+ ++startIndex;
+
+ var endIndex:int = str.length - 1;
+ while (isWhitespace(str.charAt(endIndex)))
+ --endIndex;
+
+ if (endIndex >= startIndex)
+ return str.slice(startIndex, endIndex + 1);
+ else
+ return "";
+ }
+
+ /**
+ * Removes all whitespace characters from the beginning and end
+ * of each element in an Array, where the Array is stored as a String.
+ *
+ * @param value The String whose whitespace should be trimmed.
+ *
+ * @param separator The String that delimits each Array element in the string.
+ *
+ * @return Updated String where whitespace was removed from the
+ * beginning and end of each element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function trimArrayElements(value:String, delimiter:String):String
+ {
+ if (value != "" && value != null)
+ {
+ var items:Array = value.split(delimiter);
+
+ var len:int = items.length;
+ for (var i:int = 0; i < len; i++)
+ {
+ items[i] = StringUtil.trim(items[i]);
+ }
+
+ if (len > 0)
+ {
+ value = items.join(delimiter);
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Returns true if the specified string is
+ * a single space, tab, carriage return, newline, or formfeed character.
+ *
+ * @param str The String that is is being queried.
+ *
+ * @return true if the specified string is
+ * a single space, tab, carriage return, newline, or formfeed character.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isWhitespace(character:String):Boolean
+ {
+ switch (character)
+ {
+ case " ":
+ case "\t":
+ case "\r":
+ case "\n":
+ case "\f":
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Substitutes "{n}" tokens within the specified string
+ * with the respective arguments passed in.
+ *
+ * @param str The string to make substitutions in.
+ * This string can contain special tokens of the form
+ * {n}, where n is a zero based index,
+ * that will be replaced with the additional parameters
+ * found at that index if specified.
+ *
+ * @param rest Additional parameters that can be substituted
+ * in the str parameter at each {n}
+ * location, where n is an integer (zero based)
+ * index value into the array of values specified.
+ * If the first parameter is an array this array will be used as
+ * a parameter list.
+ * This allows reuse of this routine in other methods that want to
+ * use the ... rest signature.
+ * For example
+ * public function myTracer(str:String, ... rest):void
+ * {
+ * label.text += StringUtil.substitute(str, rest) + "\n";
+ * }
+ *
+ * @return New string with all of the {n} tokens
+ * replaced with the respective arguments specified.
+ *
+ * @example
+ *
+ * var str:String = "here is some info '{0}' and {1}";
+ * trace(StringUtil.substitute(str, 15.4, true));
+ *
+ * // this will output the following string:
+ * // "here is some info '15.4' and true"
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function substitute(str:String, ... rest):String
+ {
+ if (str == null) return '';
+
+ // Replace all of the parameters in the msg string.
+ var len:uint = rest.length;
+ var args:Array;
+ if (len == 1 && rest[0] is Array)
+ {
+ args = rest[0] as Array;
+ len = args.length;
+ }
+ else
+ {
+ args = rest;
+ }
+
+ for (var i:int = 0; i < len; i++)
+ {
+ str = str.replace(new RegExp("\\{"+i+"\\}", "g"), args[i]);
+ }
+
+ return str;
+ }
+
+ /**
+ * Returns a string consisting of a specified string
+ * concatenated with itself a specified number of times.
+ *
+ * @param str The string to be repeated.
+ *
+ * @param n The repeat count.
+ *
+ * @return The repeated string.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ public static function repeat(str:String, n:int):String
+ {
+ if (n == 0)
+ return "";
+
+ var s:String = str;
+ for (var i:int = 1; i < n; i++)
+ {
+ s += str;
+ }
+ return s;
+ }
+
+ /**
+ * Removes "unallowed" characters from a string.
+ * A "restriction string" such as "A-Z0-9"
+ * is used to specify which characters are allowed.
+ * This method uses the same logic as the restrict
+ * property of TextField.
+ *
+ * @param str The input string.
+ *
+ * @param restrict The restriction string.
+ *
+ * @return The input string, minus any characters
+ * that are not allowed by the restriction string.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.1
+ */
+ public static function restrict(str:String, restrict:String):String
+ {
+ // A null 'restrict' string means all characters are allowed.
+ if (restrict == null)
+ return str;
+
+ // An empty 'restrict' string means no characters are allowed.
+ if (restrict == "")
+ return "";
+
+ // Otherwise, we need to test each character in 'str'
+ // to determine whether the 'restrict' string allows it.
+ var charCodes:Array = [];
+
+ var n:int = str.length;
+ for (var i:int = 0; i < n; i++)
+ {
+ var charCode:uint = str.charCodeAt(i);
+ if (testCharacter(charCode, restrict))
+ charCodes.push(charCode);
+ }
+
+ return String.fromCharCode.apply(null, charCodes);
+ }
+
+ /**
+ * @private
+ * Helper method used by restrict() to test each character
+ * in the input string against the restriction string.
+ * The logic in this method implements the same algorithm
+ * as in TextField's 'restrict' property (which is quirky,
+ * such as how it handles a '-' at the beginning of the
+ * restriction string).
+ */
+ private static function testCharacter(charCode:uint,
+ restrict:String):Boolean
+ {
+ var allowIt:Boolean = false;
+
+ var inBackSlash:Boolean = false;
+ var inRange:Boolean = false;
+ var setFlag:Boolean = true;
+ var lastCode:uint = 0;
+
+ var n:int = restrict.length;
+ var code:uint;
+
+ if (n > 0)
+ {
+ code = restrict.charCodeAt(0);
+ if (code == 94) // caret
+ allowIt = true;
+ }
+
+ for (var i:int = 0; i < n; i++)
+ {
+ code = restrict.charCodeAt(i)
+
+ var acceptCode:Boolean = false;
+ if (!inBackSlash)
+ {
+ if (code == 45) // hyphen
+ inRange = true;
+ else if (code == 94) // caret
+ setFlag = !setFlag;
+ else if (code == 92) // backslash
+ inBackSlash = true;
+ else
+ acceptCode = true;
+ }
+ else
+ {
+ acceptCode = true;
+ inBackSlash = false;
+ }
+
+ if (acceptCode)
+ {
+ if (inRange)
+ {
+ if (lastCode <= charCode && charCode <= code)
+ allowIt = setFlag;
+ inRange = false;
+ lastCode = 0;
+ }
+ else
+ {
+ if (charCode == code)
+ allowIt = setFlag;
+ lastCode = code;
+ }
+ }
+ }
+
+ return allowIt;
+ }
+}
+
+}
diff --git a/src/mx/utils/UIDUtil.as b/src/mx/utils/UIDUtil.as
new file mode 100644
index 00000000..9a310def
--- /dev/null
+++ b/src/mx/utils/UIDUtil.as
@@ -0,0 +1,420 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.utils
+{
+
+import flash.utils.ByteArray;
+import flash.utils.Dictionary;
+
+//import mx.core.IPropertyChangeNotifier;
+//import mx.core.IUIComponent;
+//import mx.core.IUID;
+import mx.core.mx_internal;
+
+use namespace mx_internal;
+
+/**
+ * The UIDUtil class is an all-static class
+ * with methods for working with UIDs (unique identifiers) within Flex.
+ * You do not create instances of UIDUtil;
+ * instead you simply call static methods such as the
+ * UIDUtil.createUID() method.
+ *
+ * Note: If you have a dynamic object that has no [Bindable] properties
+ * (which force the object to implement the IUID interface), Flex adds an
+ * mx_internal_uid property that contains a UID to the object.
+ * To avoid having this field
+ * in your dynamic object, make it [Bindable], implement the IUID interface
+ * in the object class, or set a
The UID has the form
+ * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
+ * where X is a hexadecimal digit (0-9, A-F).
This UID will not be truly globally unique; but it is the best + * we can do without player support for UID generation.
+ * + * @return The newly-generated UID. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public static function createUID():String + { + var uid:Array = new Array(36); + var index:int = 0; + + var i:int; + var j:int; + + for (i = 0; i < 8; i++) + { + uid[index++] = ALPHA_CHAR_CODES[Math.floor(Math.random() * 16)]; + } + + for (i = 0; i < 3; i++) + { + uid[index++] = 45; // charCode for "-" + + for (j = 0; j < 4; j++) + { + uid[index++] = ALPHA_CHAR_CODES[Math.floor(Math.random() * 16)]; + } + } + + uid[index++] = 45; // charCode for "-" + + var time:Number = new Date().getTime(); + // Note: time is the number of milliseconds since 1970, + // which is currently more than one trillion. + // We use the low 8 hex digits of this number in the UID. + // Just in case the system clock has been reset to + // Jan 1-4, 1970 (in which case this number could have only + // 1-7 hex digits), we pad on the left with 7 zeros + // before taking the low digits. + var timeString:String = ("0000000" + time.toString(16).toUpperCase()).substr(-8); + + for (i = 0; i < 8; i++) + { + uid[index++] = timeString.charCodeAt(i); + } + + for (i = 0; i < 4; i++) + { + uid[index++] = ALPHA_CHAR_CODES[Math.floor(Math.random() * 16)]; + } + + return String.fromCharCode.apply(null, uid); + } + + /** + * Converts a 128-bit UID encoded as a ByteArray to a String representation. + * The format matches that generated by createUID. If a suitable ByteArray + * is not provided, null is returned. + * + * @param ba ByteArray 16 bytes in length representing a 128-bit UID. + * + * @return String representation of the UID, or null if an invalid + * ByteArray is provided. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public static function fromByteArray(ba:ByteArray):String + { + if (ba != null && ba.length >= 16 && ba.bytesAvailable >= 16) + { + var chars:Array = new Array(36); + var index:uint = 0; + for (var i:uint = 0; i < 16; i++) + { + if (i == 4 || i == 6 || i == 8 || i == 10) + chars[index++] = 45; // Hyphen char code + + var b:int = ba.readByte(); + chars[index++] = ALPHA_CHAR_CODES[(b & 0xF0) >>> 4]; + chars[index++] = ALPHA_CHAR_CODES[(b & 0x0F)]; + } + return String.fromCharCode.apply(null, chars); + } + + return null; + } + + /** + * A utility method to check whether a String value represents a + * correctly formatted UID value. UID values are expected to be + * in the format generated by createUID(), implying that only + * capitalized A-F characters in addition to 0-9 digits are + * supported. + * + * @param uid The value to test whether it is formatted as a UID. + * + * @return Returns true if the value is formatted as a UID. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public static function isUID(uid:String):Boolean + { + if (uid != null && uid.length == 36) + { + for (var i:uint = 0; i < 36; i++) + { + var c:Number = uid.charCodeAt(i); + + // Check for correctly placed hyphens + if (i == 8 || i == 13 || i == 18 || i == 23) + { + if (c != 45) + { + return false; + } + } + // We allow capital alpha-numeric hex digits only + else if (c < 48 || c > 70 || (c > 57 && c < 65)) + { + return false; + } + } + + return true; + } + + return false; + } + + /** + * Converts a UID formatted String to a ByteArray. The UID must be in the + * format generated by createUID, otherwise null is returned. + * + * @param String representing a 128-bit UID + * + * @return ByteArray 16 bytes in length representing the 128-bits of the + * UID or null if the uid could not be converted. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public static function toByteArray(uid:String):ByteArray + { + if (isUID(uid)) + { + var result:ByteArray = new ByteArray(); + + for (var i:uint = 0; i < uid.length; i++) + { + var c:String = uid.charAt(i); + if (c == "-") + continue; + var h1:uint = getDigit(c); + i++; + var h2:uint = getDigit(uid.charAt(i)); + result.writeByte(((h1 << 4) | h2) & 0xFF); + } + result.position = 0; + return result; + } + + return null; + } + + /** + * Returns the UID (unique identifier) for the specified object. + * If the specified object doesn't have an UID + * then the method assigns one to it. + * If a map is specified this method will use the map + * to construct the UID. + * As a special case, if the item passed in is null, + * this method returns a null UID. + * + * @param item Object that we need to find the UID for. + * + * @return The UID that was either found or generated. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + *//* + public static function getUID(item:Object):String + { + var result:String = null; + + if (item == null) + return result; + + if (item is IUID) + { + result = IUID(item).uid; + if (result == null || result.length == 0) + { + result = createUID(); + IUID(item).uid = result; + } + } + else if ((item is IPropertyChangeNotifier) && + !(item is IUIComponent)) + { + result = IPropertyChangeNotifier(item).uid; + if (result == null || result.length == 0) + { + result = createUID(); + IPropertyChangeNotifier(item).uid = result; + } + } + else if (item is String) + { + return item as String; + } + else + { + try + { + // We don't create uids for XMLLists, but if + // there's only a single XML node, we'll extract it. + if (item is XMLList && item.length == 1) + item = item[0]; + + if (item is XML) + { + // XML nodes carry their UID on the + // function-that-is-a-hashtable they can carry around. + // To decorate an XML node with a UID, + // we need to first initialize it for notification. + // There is a potential performance issue here, + // since notification does have a cost, + // but most use cases for needing a UID on an XML node also + // require listening for change notifications on the node. + var xitem:XML = XML(item); + var nodeKind:String = xitem.nodeKind(); + if (nodeKind == "text" || nodeKind == "attribute") + return xitem.toString(); + + var notificationFunction:Function = xitem.notification(); + if (!(notificationFunction is Function)) + { + // The xml node hasn't already been initialized + // for notification, so do so now. + notificationFunction = + XMLNotifier.initializeXMLForNotification(); + xitem.setNotification(notificationFunction); + } + + // Generate a new uid for the node if necessary. + if (notificationFunction["uid"] == undefined) + result = notificationFunction["uid"] = createUID(); + + result = notificationFunction["uid"]; + } + else + { + if ("mx_internal_uid" in item) + return item.mx_internal_uid; + + if ("uid" in item) + return item.uid; + + result = uidDictionary[item]; + + if (!result) + { + result = createUID(); + try + { + item.mx_internal_uid = result; + } + catch(e:Error) + { + uidDictionary[item] = result; + } + } + } + } + catch(e:Error) + { + result = item.toString(); + } + } + + return result; + } +*/ + /** + * Returns the decimal representation of a hex digit. + * @private + */ + private static function getDigit(hex:String):uint + { + switch (hex) + { + case "A": + case "a": + return 10; + case "B": + case "b": + return 11; + case "C": + case "c": + return 12; + case "D": + case "d": + return 13; + case "E": + case "e": + return 14; + case "F": + case "f": + return 15; + default: + return new uint(hex); + } + } +} + +} diff --git a/src/mx/utils/XMLNotifier.as b/src/mx/utils/XMLNotifier.as new file mode 100644 index 00000000..58e74583 --- /dev/null +++ b/src/mx/utils/XMLNotifier.as @@ -0,0 +1,256 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// ADOBE SYSTEMS INCORPORATED +// Copyright 2005-2007 Adobe Systems Incorporated +// All Rights Reserved. +// +// NOTICE: Adobe permits you to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.utils +{ + +import flash.utils.Dictionary; +import mx.core.mx_internal; +import mx.utils.IXMLNotifiable; + +use namespace mx_internal; + +/** + * Used for watching changes to XML and XMLList objects. + * Those objects are not EventDispatchers, so if multiple elements + * want to watch for changes they need to go through this mechanism. + * CallwatchXML(), passing in the same notification
+ * function that you would pass to XML.notification.
+ * Use unwatchXML() to remove that notification.
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class XMLNotifier
+{
+ include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * XMLNotifier is a singleton.
+ */
+ private static var instance:XMLNotifier;
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Get the singleton instance of the XMLNotifier.
+ *
+ * @return The XMLNotifier object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function getInstance():XMLNotifier
+ {
+ if (!instance)
+ instance = new XMLNotifier(new XMLNotifierSingleton());
+
+ return instance;
+ }
+
+ /**
+ * @private
+ * Decorates an XML node with a notification function
+ * that can fan out to multiple targets.
+ */
+ mx_internal static function initializeXMLForNotification():Function
+ {
+ var notificationFunction:Function = function(currentTarget:Object,
+ ty:String,
+ tar:Object,
+ value:Object,
+ detail:Object):void
+ {
+ var xmlWatchers:Dictionary = arguments.callee.watched;
+ if (xmlWatchers != null)
+ {
+ for (var notifiable:Object in xmlWatchers)
+ {
+ IXMLNotifiable(notifiable).xmlNotification(currentTarget, ty, tar, value, detail);
+ }
+ }
+ }
+
+ return notificationFunction;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * XMLNotifier is a singleton class, so you do not use
+ * the new operator to create multiple instances of it.
+ * Instead, call the static method XMLNotifider.getInstance()
+ * to get the sole instance of this class.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function XMLNotifier(x:XMLNotifierSingleton)
+ {
+ super();
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Given an XML or XMLList, add the notification function
+ * to watch for changes.
+ *
+ * @param xml XML/XMLList object to watch.
+ * @param notification Function that needs to be called.
+ * @param optional UID for object
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function watchXML(xml:Object, notifiable:IXMLNotifiable, uid:String = null):void
+ {
+ if ((xml is XMLList) && xml.length() > 1)
+ {
+ for each(var item:Object in xml)
+ {
+ watchXML(item, notifiable, uid);
+ }
+ }
+ else
+ {
+ // An XMLList object behaves like XML when it contains one
+ // XML object. Casting to an XML object is necessary to
+ // access the notification() function.
+ var xmlItem:XML = XML(xml);
+
+ // First make sure the xml node has a notification function.
+ var watcherFunction:Object = xmlItem.notification();
+
+ if (!(watcherFunction is Function))
+ {
+ watcherFunction = initializeXMLForNotification();
+ xmlItem.setNotification(watcherFunction as Function);
+ if (uid && watcherFunction["uid"] == null)
+ watcherFunction["uid"] = uid;
+ }
+
+ // Watch lists are maintained on the notification function.
+ var xmlWatchers:Dictionary;
+ if (watcherFunction["watched"] == undefined)
+ watcherFunction["watched"] = xmlWatchers = new Dictionary(true);
+ else
+ xmlWatchers = watcherFunction["watched"];
+
+ xmlWatchers[notifiable] = true;
+ }
+ }
+
+ /**
+ * Given an XML or XMLList, remove the specified notification function.
+ *
+ * @param xml XML/XMLList object to un-watch.
+ * @param notification Function notification function.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function unwatchXML(xml:Object, notifiable:IXMLNotifiable):void
+ {
+ if ((xml is XMLList) && xml.length() > 1)
+ {
+ for each(var item:Object in xml)
+ {
+ unwatchXML(item, notifiable);
+ }
+ }
+ else
+ {
+ // An XMLList object behaves like XML when it contains one
+ // XML object. Casting to an XML object is necessary to
+ // access the notification() function.
+ var xmlItem:XML = XML(xml);
+
+ var watcherFunction:Object = xmlItem.notification();
+
+ if (!(watcherFunction is Function))
+ return;
+
+ var xmlWatchers:Dictionary;
+
+ if (watcherFunction["watched"] != undefined)
+ {
+ xmlWatchers = watcherFunction["watched"];
+ delete xmlWatchers[notifiable];
+ }
+ }
+ }
+}
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Helper class: XMLNotifierSingleton
+//
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @private
+ */
+class XMLNotifierSingleton
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function XMLNotifierSingleton()
+ {
+ super();
+ }
+}
diff --git a/src/reflex/animation/AnimationToken.as b/src/reflex/animation/AnimationToken.as
new file mode 100644
index 00000000..0160c262
--- /dev/null
+++ b/src/reflex/animation/AnimationToken.as
@@ -0,0 +1,28 @@
+package reflex.animation
+{
+ public dynamic class AnimationToken
+ {
+
+ public var x:Number;
+ public var y:Number;
+ public var z:Number;
+
+ public var width:Number;
+ public var height:Number;
+
+ public var rotationX:Number = 0;
+ public var rotationY:Number = 0;
+ public var rotationZ:Number = 0;
+
+ //public var alpha:Number = 1.0;
+
+ public function AnimationToken(x:Number, y:Number, width:Number, height:Number)
+ {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/animation/AnimationType.as b/src/reflex/animation/AnimationType.as
new file mode 100644
index 00000000..a41273fe
--- /dev/null
+++ b/src/reflex/animation/AnimationType.as
@@ -0,0 +1,20 @@
+package reflex.animation
+{
+ public class AnimationType
+ {
+
+ static public const GENERIC:String = "generic";
+ static public const LAYOUT:String = "layout";
+ static public const RESIZE:String = "resize";
+ static public const ADD:String = "add";
+ static public const REMOVE:String = "remove";
+ static public const REPLACE:String = "replace";
+ static public const RESET:String = "reset";
+ static public const SCROLL:String = "scroll";
+ static public const DRAG:String = "drag";
+
+ public function AnimationType()
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/animation/Animator.as b/src/reflex/animation/Animator.as
new file mode 100644
index 00000000..5ecef7b6
--- /dev/null
+++ b/src/reflex/animation/Animator.as
@@ -0,0 +1,54 @@
+package reflex.animation
+{
+
+ import reflex.framework.IMeasurable;
+
+ public class Animator implements IAnimator
+ {
+ public function Animator()
+ {
+ }
+
+ public function createAnimationToken(renderer:Object):AnimationToken {
+ try { // todo: sometimes renderer is still data - but it shouldn't be - check container content validate() call
+ var token:AnimationToken = new AnimationToken(renderer.x, renderer.y, renderer.width, renderer.height);
+ } catch(error:Error) {
+ return new AnimationToken(0, 0, 0, 0);
+ }
+ //token.alpha = renderer.alpha;
+ //if(renderer is DisplayObject) { token.matrix = renderer.transform.matrix; }
+ return token;
+ }
+
+
+ public function begin():void {}
+
+ public function moveItem(item:Object, token:AnimationToken, type:String):void
+ {
+ move(item, token);
+ }
+
+ public function end():void {}
+
+ private function move(item:Object, token:AnimationToken):void {
+ try { // todo: sometimes renderer is still data - but it shouldn't be - check container content validate() call
+ item.x = token.x;
+ item.y = token.y;
+
+ if(item is IMeasurable) {
+ (item as IMeasurable).setSize(token.width, token.height);
+ } else {
+ item.width = token.width;
+ item.height = token.height;
+ }
+ //item.rotationZ = token.rotation;
+ //if(item is DisplayObject) {
+ //item.transform.matrix = token.matrix;
+ //}
+ } catch (e:Error) {
+
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/animation/IAnimator.as b/src/reflex/animation/IAnimator.as
new file mode 100644
index 00000000..445da780
--- /dev/null
+++ b/src/reflex/animation/IAnimator.as
@@ -0,0 +1,36 @@
+package reflex.animation
+{
+ import flash.display.DisplayObject;
+
+ import reflex.animation.AnimationToken;
+
+ public interface IAnimator
+ {
+
+ function createAnimationToken(renderer:Object):AnimationToken;
+
+ /**
+ * attaches this animator to a given container
+ */
+ //function attach(container:Object):void;
+ //function detach(container:Object):void;
+
+
+ /**
+ * Called before a series of addItem, moveItem, or removeItem calls.
+ */
+ function begin():void;
+
+ // we might break these up into seperate interfaces later
+ //function addItem(item:Object):void;
+ function moveItem(item:Object, token:AnimationToken, type:String):void;
+ //function adjustItem(item:Object, token:AnimationToken):void; // for scrolling, drag reactions etc.
+ //function removeItem(item:Object, callback:Function):void;
+
+ /**
+ * Called after a series of addItem, moveItem, or removeItem calls.
+ */
+ function end():void;
+
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/behaviors/Behavior.as b/src/reflex/behaviors/Behavior.as
index 8ce3df1c..4542745c 100644
--- a/src/reflex/behaviors/Behavior.as
+++ b/src/reflex/behaviors/Behavior.as
@@ -1,17 +1,14 @@
-package reflex.behaviors
+package reflex.behaviors
{
- import flash.display.InteractiveObject;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
- import flight.binding.Bind;
- import flight.utils.Type;
-
+ import reflex.display.PropertyDispatcher;
+ import reflex.events.DataChangeEvent;
import reflex.metadata.resolveBindings;
+ import reflex.metadata.resolveDataListeners;
import reflex.metadata.resolveEventListeners;
- import reflex.metadata.resolvePropertyListeners;
- import reflex.skins.ISkinnable;
/**
* Behavior is a convenient base class for various behavior implementations.
@@ -19,121 +16,31 @@ package reflex.behaviors
* InteractiveObject. Behavior takes advantage of the skin of an ISkinnable
* target by syncing skin parts and setting state.
*
- * Reflex component behaviors can be broken into 3 types -
- * 1) a components single base behavior - core implementation with which the
- * particular component would be useless without (eg ScrollBarBehavior)
- * 2) a components addon behaviors - additional functionality specefic to
- * the component (eg ReorderTabBehavior)
- * 3) common addon behaviors - general solutions for all components, or all
- * components of a type (eg TooltipBehavior)
* @alpha
*/
- public class Behavior extends EventDispatcher implements IBehavior
+ public class Behavior extends PropertyDispatcher implements IBehavior
{
+
+ private var _target:IEventDispatcher;
+
/**
* The object this behavior acts upon.
*/
- [Bindable]
- public var target:IEventDispatcher;
+ [Bindable(event="targetChange")]
+ public function get target():IEventDispatcher { return _target; }
+ public function set target(value:IEventDispatcher):void {
+ notify("target", _target, _target = value);
+ }
+
- // TODO: add SkinParts with support for adding child behaviors to them
- // registration of Behavior instances (via styling?) for instantiation
- // skins ability to pull behavior data for state and other use
- // skins also need data such as labels and images? (localization?)
- // and dynamic data for it's content-area (component children)
public function Behavior(target:IEventDispatcher = null)
{
- this.target = target;
+ super(this);
+ _target = target; // binding
reflex.metadata.resolveBindings(this);
- reflex.metadata.resolvePropertyListeners(this);
+ reflex.metadata.resolveDataListeners(this);
reflex.metadata.resolveEventListeners(this);
}
- protected function getSkinPart(part:String):InteractiveObject
- {
- if (target is ISkinnable && ISkinnable(target).skin != null) {
- return ISkinnable(target).skin.getSkinPart(part) as InteractiveObject;
- } else if (part in target) {
- return target[part] as InteractiveObject;
- } else {
- return null;
- }
- }
- /*
- protected function bindProperty(target:String, source:String):void
- {
- Bind.addBinding(this, target, this, source, true);
- }
-
- protected function bindPropertyListener(target:String, listener:Function):void
- {
- Bind.addListener(this, listener, this, target);
- }
-
- protected function bindEventListener(type:String, target:String, listener:Function,
- useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = true):void
- {
- Bind.bindEventListener(type, listener, this, target, useCapture, priority, useWeakReference);
- }
- */
- /*
- // parses [Binding(target="target.path")] metadata
- public static function describeBindings(behavior:IBehavior):void
- {
- var desc:XMLList = Type.describeProperties(behavior, "Binding");
-
- for each (var prop:XML in desc) {
- var meta:XMLList = prop.metadata.(@name == "Binding");
-
- // to support multiple Binding metadata tags on a single property
- for each (var tag:XML in meta) {
- var targ:String = ( tag.arg.(@key == "target").length() > 0 ) ?
- tag.arg.(@key == "target").@value :
- tag.arg.@value;
-
- Bind.addBinding(behavior, targ, behavior, prop.@name, true);
- }
- }
- }
-
- // parses [PropertyListener(target="target.path)] metadata
- public static function describePropertyListeners(behavior:IBehavior):void
- {
- var desc:XMLList = Type.describeMethods(behavior, "PropertyListener");
-
- for each (var meth:XML in desc) {
- var meta:XMLList = meth.metadata.(@name == "PropertyListener");
-
- // to support multiple PropertyListener metadata tags on a single method
- for each (var tag:XML in meta) {
- var targ:String = ( tag.arg.(@key == "target").length() > 0 ) ?
- tag.arg.(@key == "target").@value :
- tag.arg.@value;
-
- Bind.addListener(behavior as IEventDispatcher, behavior[meth.@name], behavior, targ);
- }
- }
- }
-
- // parses [EventListener(type="eventType", target="target.path")] metadata
- public static function describeEventListeners(behavior:IBehavior):void
- {
- var desc:XMLList = Type.describeMethods(behavior, "EventListener");
-
- for each (var meth:XML in desc) {
- var meta:XMLList = meth.metadata.(@name == "EventListener");
-
- // to support multiple EventListener metadata tags on a single method
- for each (var tag:XML in meta) {
- var type:String = ( tag.arg.(@key == "type").length() > 0 ) ?
- tag.arg.(@key == "type").@value :
- tag.arg.@value;
- var targ:String = tag.arg.(@key == "target").@value;
-
- Bind.bindEventListener(type, behavior[meth.@name], behavior, targ);
- }
- }
- }
- */
}
}
\ No newline at end of file
diff --git a/src/reflex/behaviors/ButtonBehavior.as b/src/reflex/behaviors/ButtonBehavior.as
index 37ff2aa8..3c43cc6b 100644
--- a/src/reflex/behaviors/ButtonBehavior.as
+++ b/src/reflex/behaviors/ButtonBehavior.as
@@ -1,18 +1,17 @@
package reflex.behaviors
{
- import flash.display.DisplayObjectContainer;
- import flash.display.InteractiveObject;
+
import flash.events.IEventDispatcher;
import flash.events.MouseEvent;
- import flight.binding.Bind;
-
- import reflex.events.ButtonEvent;
- import reflex.skins.ISkinnable;
+ import reflex.skins.ISkin;
+
+ //import reflex.events.ButtonEvent;
[SkinState("up")]
[SkinState("over")]
[SkinState("down")]
+ [SkinState("disabled")]
[Event(name="buttonDown", type="mx.events.FlexEvent")]
@@ -21,56 +20,104 @@ package reflex.behaviors
*/
public class ButtonBehavior extends Behavior implements IBehavior
{
+
public static const UP:String = "up";
public static const OVER:String = "over";
public static const DOWN:String = "down";
+ public static const DISABLED:String = "disabled";
+
+ //public static const SELECTED_UP:String = "upAndSelected";
+ //public static const SELECTED_OVER:String = "overAndSelected";
+ //public static const SELECTED_DOWN:String = "downAndSelected";
+
+
+ private var _currentState:String = UP;
+ private var _enabled:Boolean = true;
+ private var _selected:Boolean = false;
+ private var mouseState:String = UP;
+ private var _skin:ISkin;
+ private var _mouseEnabled:Boolean = true;
- [Bindable]
+ [Bindable(event="currentStateChange")]
[Binding(target="target.currentState")]
- public var currentState:String = UP;
+ public function get currentState():String { return _currentState; }
+ public function set currentState(value:String):void {
+ notify("currentState", _currentState, _currentState = value);
+ }
- public function ButtonBehavior(target:InteractiveObject = null)
- {
- super(target);
+ [Bindable(event="enabledChange")]
+ [Binding(target="target.enabled")]
+ public function get enabled():Boolean { return _enabled; }
+ public function set enabled(value:Boolean):void {
+ notify("enabled", _enabled, _enabled = value);
+ currentState = resolveState(mouseState);
}
- override public function set target(value:IEventDispatcher):void
- {
- if (value != null) {
- if (value is DisplayObjectContainer) {
- DisplayObjectContainer(value).mouseChildren = false;
- }
- ButtonEvent.initialize(value);
- }
- super.target = value;
+ [Bindable(event="selectedChange")]
+ [Binding(target="target.selected")]
+ public function get selected():Boolean { return _selected; }
+ public function set selected(value:Boolean):void {
+ notify("selected", _selected, _selected = value);
+ currentState = resolveState(mouseState);
}
- public function click():void
- {
- target.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
+ [Bindable(event="skinChange")]
+ [Binding(target="target.skin")]
+ public function get skin():ISkin { return _skin; }
+ public function set skin(value:ISkin):void {
+ notify("skin", _skin, _skin = value);
+ currentState = resolveState(mouseState);
+ }
+
+ [Bindable(event="mouseEnabledChange")]
+ public function get mouseEnabled():Boolean { return _mouseEnabled; }
+ public function set mouseEnabled(value:Boolean):void {
+ notify("mouseEnabled", _mouseEnabled, _mouseEnabled = value);
+ }
+
+ public function ButtonBehavior(target:IEventDispatcher = null) {
+ super(target);
}
// ====== Event Listeners ====== //
- [EventListener(type="stateUp", target="target")]
+ [EventListener(event="rollOut", target="target.display")]
+ [EventListener(event="releaseOutside", target="target.display.stage")]
public function onStateUp(event:MouseEvent):void
{
- currentState = UP;
- event.updateAfterEvent();
+ currentState = resolveState(mouseState = UP);
}
- [EventListener(type="stateOver", target="target")]
+ [EventListener(event="rollOver", target="target.display")]
+ [EventListener(event="mouseUp", target="target.display")]
public function onStateOver(event:MouseEvent):void
{
- currentState = OVER;
- event.updateAfterEvent();
+ if(_mouseEnabled) {
+ currentState = resolveState(mouseState = OVER);
+ }
}
- [EventListener(type="stateDown", target="target")]
+ [EventListener(event="mouseDown", target="target.display")]
public function onStateDown(event:MouseEvent):void
{
- currentState = DOWN;
- event.updateAfterEvent();
+ if(_mouseEnabled) {
+ currentState = resolveState(mouseState = DOWN);
+ }
+ }
+
+ private function resolveState(mouseState:String):String {
+ if(_skin) {
+ if(!_enabled && _skin.hasState(DISABLED)) {
+ return DISABLED;
+ }
+ if(_selected && _skin.hasState(mouseState + "AndSelected")) {
+ return mouseState + "AndSelected";
+ }
+ if(_skin.hasState(mouseState)) {
+ return mouseState;
+ }
+ }
+ return _selected ? mouseState + "AndSelected" : mouseState;
}
}
diff --git a/src/reflex/behaviors/CompositeBehavior.as b/src/reflex/behaviors/CompositeBehavior.as
deleted file mode 100644
index 8d1140b7..00000000
--- a/src/reflex/behaviors/CompositeBehavior.as
+++ /dev/null
@@ -1,258 +0,0 @@
-package reflex.behaviors
-{
- import flash.display.InteractiveObject;
- import flash.events.Event;
- import flash.events.EventDispatcher;
- import flash.events.IEventDispatcher;
- import flash.utils.Dictionary;
- import flash.utils.Proxy;
- import flash.utils.flash_proxy;
-
-
- use namespace flash_proxy;
-
- /**
- * A dynamic proxy for compositing multiple behaviors. The CompositeBehavior
- * may be iterated through just as an Array might be.
- */
- public dynamic class CompositeBehavior extends Proxy implements IBehavior, IEventDispatcher
- {
-
- private var _target:IEventDispatcher;
-
- private var behaviors:Array;
- private var dictionary:Dictionary;
- private var dispatcher:EventDispatcher;
-
-
- /**
- * Constructor.
- *
- * @param The target for this behavior map.
- */
- public function CompositeBehavior(target:IEventDispatcher = null)
- {
- _target = target;
- behaviors = [];
- dictionary = new Dictionary(false);
- }
-
-
- [Bindable("targetChange")]
- /**
- * The object which the behaviors in this map will act upon.
- */
- public function get target():IEventDispatcher
- {
- return _target;
- }
-
- public function set target(value:IEventDispatcher):void
- {
- if (value == _target) return;
- _target = value;
- for each (var behavior:IBehavior in dictionary) {
- behavior.target = value;
- }
- dispatch("targetChange");
- }
-
-
- public function get length():uint {
- return behaviors.length;
- }
- public function set length(value:uint):void {
- // remove target from truncated items?
- behaviors.length = value;
- }
-
- //[ArrayElementType("reflex.core.IBehavior")]
- public function add(item:Object):uint
- {
- if(item is IBehavior) {
- (item as IBehavior).target = _target;
- behaviors.push(item as IBehavior);
- } else if(item is Array) {
- for each (var behavior:IBehavior in item) {
- behavior.target = _target;
- behaviors.push(behavior);
- }
- }
- return behaviors.length;
- }
-
- public function clear():Array {
- for each(var behavior:IBehavior in behaviors) {
- behavior.target = null;
- //delete dictionary[behavior];
- }
- behaviors = [];
- dictionary = new Dictionary(); // delete keys instead
- return null;
- }
-
- /**
- * Proxy method to return a requested property.
- */
- override flash_proxy function getProperty(name:*):*
- {
- return behaviors[name];
- }
-
-
- /**
- * Proxy method to set a property. Accepts a Class object for an
- * IBehavior or an IBehavior object itself.
- */
- override flash_proxy function setProperty(name:*, value:*):void
- {
- var oldBehavior:IBehavior = behaviors[name] as IBehavior;
- if (value is Class) { // allow classes to be used to set behaviors
- if (oldBehavior is value) return;
- value = new value();
- }
-
- if (value == oldBehavior) return;
- if (value == null) {
- deleteProperty(name);
- return;
- }
-
- if (value != null && !(value is IBehavior) ) {
- throw new ArgumentError("Only IBehavior objects can be added to behaviors.");
- }
-
- if (oldBehavior) {
- oldBehavior.target = null;
- }
-
- var behavior:IBehavior = value as IBehavior;
-
- if (behavior) {
- behavior.target = target;
- }
- behaviors[name] = behavior;
- dispatch(name + "Change");
- }
-
-
- /**
- * Proxy method to delete the specified property.
- */
- override flash_proxy function deleteProperty(name:*):Boolean
- {
- var behavior:IBehavior = behaviors[name] as IBehavior;
- if (behavior) {
- behavior.target = null;
- }
- return delete behaviors[name];
- }
-
-
- /**
- * Proxy method to check if the specified property exists.
- */
- override flash_proxy function hasProperty(name:*):Boolean
- {
- return (name in behaviors);
- }
-
-
- /**
- * to be determined
- */
- override flash_proxy function callProperty(name:*, ...rest):*
- {
- return null;
- }
-
-
- private var props:Array;
-
- /**
- * Proxy method allowing looping through the map.
- */
- override flash_proxy function nextName(index:int):String
- {
- return (index - 1).toString();
- }
-
- /**
- * Proxy method allowing looping through the map.
- */
- override flash_proxy function nextValue(index:int):*
- {
- return behaviors[index-1];
- }
-
- /**
- * Proxy method allowing looping through the map.
- */
- override flash_proxy function nextNameIndex(index:int):int
- {
- if(index < behaviors.length) {
- return index + 1;
- } else {
- return 0;
- }
- //return (index + 1) % (props.length + 1); // returns 0 when it hits length
- }
-
-
-
- // ========== Dispatcher Methods ========== //
-
- public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
- {
- if (dispatcher == null) {
- dispatcher = new EventDispatcher(this);
- }
-
- dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
- }
-
-
- public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
- {
- if (dispatcher != null) {
- dispatcher.removeEventListener(type, listener, useCapture);
- }
- }
-
-
- public function dispatchEvent(event:Event):Boolean
- {
- if (dispatcher != null && dispatcher.hasEventListener(event.type)) {
- return dispatcher.dispatchEvent(event);
- }
- return false;
- }
-
-
- public function hasEventListener(type:String):Boolean
- {
- if (dispatcher != null) {
- return dispatcher.hasEventListener(type);
- }
- return false;
- }
-
-
- public function willTrigger(type:String):Boolean
- {
- if (dispatcher != null) {
- return dispatcher.willTrigger(type);
- }
- return false;
- }
-
-
- protected function dispatch(type:String):Boolean
- {
- if (dispatcher != null && dispatcher.hasEventListener(type)) {
- return dispatcher.dispatchEvent( new Event(type) );
- }
- return false;
- }
- }
-}
\ No newline at end of file
diff --git a/src/reflex/behaviors/CursorBehavior.as b/src/reflex/behaviors/CursorBehavior.as
deleted file mode 100644
index 6de02985..00000000
--- a/src/reflex/behaviors/CursorBehavior.as
+++ /dev/null
@@ -1,35 +0,0 @@
-package reflex.behaviors
-{
- import flash.display.DisplayObject;
- import flash.display.InteractiveObject;
-
- import flight.binding.Bind;
-
- import reflex.cursors.Cursor;
-
- public class CursorBehavior extends Behavior
- {
- [Bindable]
- public var cursor:Object;
-
- public function CursorBehavior(target:IEventDispatcher=null)
- {
- super(target);
- Bind.addListener(this, cursorChange, this, "cursor");
- Bind.addListener(this, targetChange, this, "target");
- }
-
- protected function cursorChange(cursor:Object):void
- {
- if (target) {
- Cursor.useCursor(target, cursor);
- }
- }
-
- protected function targetChange(oldTarget:InteractiveObject, newTarget:InteractiveObject):void
- {
- if (oldTarget && cursor) Cursor.useCursor(oldTarget, null);
- if (newTarget && cursor) Cursor.useCursor(newTarget, cursor);
- }
- }
-}
\ No newline at end of file
diff --git a/src/reflex/behaviors/DragBehavior.as b/src/reflex/behaviors/DragBehavior.as
deleted file mode 100644
index 2e3a14c3..00000000
--- a/src/reflex/behaviors/DragBehavior.as
+++ /dev/null
@@ -1,54 +0,0 @@
-package reflex.behaviors
-{
- import flash.display.DisplayObjectContainer;
- import flash.display.InteractiveObject;
- import flash.events.IEventDispatcher;
- import flash.events.MouseEvent;
- import flash.geom.Point;
-
- import reflex.events.ButtonEvent;
-
- public class DragBehavior extends Behavior
- {
- private var startMouse:Point;
- private var startPosition:Point;
-
- public function DragBehavior(target:InteractiveObject=null)
- {
- super(target);
- }
-
- override public function set target(value:IEventDispatcher):void
- {
- if (value != null) {
- ButtonEvent.initialize(value);
- }
- super.target = value;
- }
-
-
- // ====== Event Listeners ====== //
-
- [EventListener(type="mouseDown", target="target")]
- public function onMouseDown(event:MouseEvent):void
- {
- var item:InteractiveObject = event.currentTarget as InteractiveObject;
- startMouse = new Point(event.stageX, event.stageY);
- startPosition = new Point(item.x, item.y);
- startPosition = item.parent.localToGlobal(startPosition);
- }
-
- [EventListener(type="drag", target="target")]
- public function onDrag(event:MouseEvent):void
- {
- var item:InteractiveObject = event.currentTarget as InteractiveObject;
- var mouse:Point = new Point(event.stageX, event.stageY);
- var delta:Point = mouse.subtract(startMouse);
- var position:Point = startPosition.add(delta);
- position = item.parent.globalToLocal(position);
- item.x = position.x;
- item.y = position.y;
- event.updateAfterEvent();
- }
- }
-}
\ No newline at end of file
diff --git a/src/reflex/behaviors/DragListBehavior.as b/src/reflex/behaviors/DragListBehavior.as
new file mode 100644
index 00000000..86bc2243
--- /dev/null
+++ b/src/reflex/behaviors/DragListBehavior.as
@@ -0,0 +1,74 @@
+package reflex.behaviors
+{
+ import flash.events.IEventDispatcher;
+ import flash.events.MouseEvent;
+
+ import reflex.events.ContainerEvent;
+ import reflex.features.IDragManager;
+ import reflex.framework.IDataContainer;
+
+ public class DragListBehavior extends Behavior
+ {
+
+ private var _container:IDataContainer;
+ private var renderers:Array;
+
+ [Inject]
+ public var drag:IDragManager;
+
+ [Bindable(event="containerChange")]
+ [Binding(target="target.skin.container")]
+ public function get container():IDataContainer { return _container; }
+ public function set container(value:IDataContainer):void {
+ var renderer:IEventDispatcher;
+ if(_container) {
+ (_container as IEventDispatcher).removeEventListener(ContainerEvent.ITEM_ADDED, onItemAdded, false);
+ while(renderers.length > 0) {
+ renderer = renderers.pop() as IEventDispatcher;
+ renderer.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown, false);
+ }
+ }
+ notify("container", _container, _container = value);
+ if(_container) {
+ (_container as IEventDispatcher).addEventListener(ContainerEvent.ITEM_ADDED, onItemAdded, false, 0, true);
+ renderers = _container.getRenderers();
+
+ for each(renderer in renderers) {
+ renderer.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown, false, 0, true);
+ }
+ }
+ }
+
+ [EventListener(event="itemAdded", target="container")]
+ public function onItemAdded(event:ContainerEvent):void
+ {
+ var renderer:IEventDispatcher = event.renderer as IEventDispatcher;
+ if(renderer) { renderer.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown, false, 0, true); }
+ }
+
+ private var renderer:Object;
+ private function onMouseDown(event:MouseEvent):void {
+ renderer = event.currentTarget;
+ var stage:IEventDispatcher = renderer.display.stage;
+ stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove, false, 0, true);
+ stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp, false, 0, true);
+ }
+
+ private function onMouseMove(event:MouseEvent):void {
+
+ var item:* = _container.getItemForRenderer(renderer);
+ drag.doDrag(renderer, item);
+ var stage:IEventDispatcher = event.currentTarget as IEventDispatcher;
+ stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove, false);
+ //stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseMove, false);
+ }
+
+ private function onMouseUp(event:MouseEvent):void {
+ var stage:IEventDispatcher = event.currentTarget as IEventDispatcher;
+ stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove, false);
+ stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseMove, false);
+ drag.endDrag();
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/behaviors/DragStepBehavior.as b/src/reflex/behaviors/DragStepBehavior.as
index 364e4f05..b2a08645 100644
--- a/src/reflex/behaviors/DragStepBehavior.as
+++ b/src/reflex/behaviors/DragStepBehavior.as
@@ -1,23 +1,29 @@
package reflex.behaviors
{
- import flash.display.InteractiveObject;
- import flash.display.MovieClip;
+
+ import flash.events.Event;
import flash.events.IEventDispatcher;
import flash.events.MouseEvent;
- import flight.binding.Bind;
- import flight.position.IPosition;
- import flight.position.Position;
-
- import reflex.events.ButtonEvent;
+ import reflex.data.IPosition;
public class DragStepBehavior extends Behavior
{
- [Bindable]
+
+ private var _position:IPosition;
+
+ [Bindable(event="positionChange")]
[Binding(target="target.position")]
- public var position:IPosition = new Position(); // TODO: implement lazy instantiation of position
+ public function get position():IPosition { return _position; }
+ public function set position(value:IPosition):void {
+ notify("position", _position, _position = value);
+ }
+
+ public var increment:Number = 1;
+ public var dragTolerance:Number = 3;
+ public var dragging:Boolean = false;
- protected var startDragPosition:Number;
+ private var startDragPosition:Number;
public function DragStepBehavior(target:IEventDispatcher = null)
{
@@ -32,19 +38,24 @@ package reflex.behaviors
return;
}
- ButtonEvent.initialize(target);
+ //ButtonEvent.initialize(target);
}
- [EventListener(type="mouseDown", target="target")]
+ [EventListener(event="mouseDown", target="target")]
public function onDragStart(event:MouseEvent):void
{
startDragPosition = position.value;
}
- [EventListener(type="drag", target="target")]
- public function onDrag(event:ButtonEvent):void
+ [EventListener(event="drag", target="target")]
+ public function onDrag(event:Event):void
{
- position.value = startDragPosition + event.deltaX;
+ if (dragging) {
+ //position.value = Math.round( (startDragPosition + event.deltaX) / increment) * increment;
+ //} else if ( Math.abs(startDragPosition - event.deltaX) > dragTolerance) {
+ //position.value = Math.round( (startDragPosition + event.deltaX) / increment) * increment;
+ //dragging = true;
+ }
}
}
diff --git a/src/reflex/behaviors/DropListBehavior.as b/src/reflex/behaviors/DropListBehavior.as
new file mode 100644
index 00000000..3f6c8172
--- /dev/null
+++ b/src/reflex/behaviors/DropListBehavior.as
@@ -0,0 +1,39 @@
+package reflex.behaviors
+{
+ import flash.events.IEventDispatcher;
+ import flash.events.MouseEvent;
+
+ import reflex.containers.IContainer;
+ import reflex.features.IDragManager;
+
+ public class DropListBehavior extends Behavior
+ {
+
+ private var _container:IContainer;
+
+ [Inject]
+ public var drag:IDragManager;
+
+ [Bindable(event="containerChange")]
+ [Binding(target="target.skin.container")]
+ public function get container():IContainer { return _container; }
+ public function set container(value:IContainer):void {
+ var renderer:IEventDispatcher;
+ if(_container) {
+ //(_container as IEventDispatcher).removeEventListener(MouseEvent.MOUSE_OVER, onMouseOver, false);
+ }
+ notify("container", _container, _container = value);
+ if(_container) {
+ //(_container as IEventDispatcher).addEventListener(MouseEvent.MOUSE_OVER, onMouseOver, false, 0, true);
+ }
+ }
+ /*
+ private function onMouseOver(event:MouseEvent):void {
+ if(drag.isDragging()) {
+ //this.addEventListener(DragEvent.DRAG_DROP, onDragDrop, false, 0, true);
+ drag.acceptDragDrop(container);
+ }
+ }
+ */
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/behaviors/IBehavior.as b/src/reflex/behaviors/IBehavior.as
index f9be732a..6f74655b 100644
--- a/src/reflex/behaviors/IBehavior.as
+++ b/src/reflex/behaviors/IBehavior.as
@@ -1,6 +1,6 @@
package reflex.behaviors
{
- import flash.display.InteractiveObject;
+
import flash.events.IEventDispatcher;
/**
diff --git a/src/reflex/behaviors/IBehavioral.as b/src/reflex/behaviors/IBehavioral.as
deleted file mode 100644
index b031b3ab..00000000
--- a/src/reflex/behaviors/IBehavioral.as
+++ /dev/null
@@ -1,9 +0,0 @@
-package reflex.behaviors
-{
-
- public interface IBehavioral
- {
- function get behaviors():CompositeBehavior;
- function set behaviors(value:*):void;
- }
-}
\ No newline at end of file
diff --git a/src/reflex/behaviors/ListBehavior.as b/src/reflex/behaviors/ListBehavior.as
index 83c921d2..441149e5 100644
--- a/src/reflex/behaviors/ListBehavior.as
+++ b/src/reflex/behaviors/ListBehavior.as
@@ -2,9 +2,6 @@ package reflex.behaviors
{
import flash.display.InteractiveObject;
import flash.events.IEventDispatcher;
-
- import reflex.skins.ISkin;
- import reflex.skins.ISkinnable;
public class ListBehavior extends Behavior
{
@@ -28,8 +25,8 @@ package reflex.behaviors
//var skin:ISkin = ISkinnable(target).skin;
- hScrollBar = getSkinPart('hScrollBar');
- vScrollBar = getSkinPart('vScrollBar');
+ //hScrollBar = getSkinPart('hScrollBar');
+ //vScrollBar = getSkinPart('vScrollBar');
hSlideBehavior = new SlideBehavior();
vSlideBehavior = new SlideBehavior();
diff --git a/src/reflex/behaviors/ListSelectBehavior.as b/src/reflex/behaviors/ListSelectBehavior.as
deleted file mode 100644
index 5e32565c..00000000
--- a/src/reflex/behaviors/ListSelectBehavior.as
+++ /dev/null
@@ -1,9 +0,0 @@
-package reflex.behaviors
-{
- public class ListSelectBehavior
- {
- public function ListSelectBehavior()
- {
- }
- }
-}
\ No newline at end of file
diff --git a/src/reflex/behaviors/ListSelectionBehavior.as b/src/reflex/behaviors/ListSelectionBehavior.as
new file mode 100644
index 00000000..f9757a9a
--- /dev/null
+++ b/src/reflex/behaviors/ListSelectionBehavior.as
@@ -0,0 +1,162 @@
+package reflex.behaviors
+{
+
+ import flash.display.DisplayObjectContainer;
+ import flash.events.Event;
+ import flash.events.IEventDispatcher;
+ import flash.events.MouseEvent;
+ import flash.ui.Mouse;
+
+ import mx.collections.IList;
+ import mx.core.IDataRenderer;
+ import mx.events.CollectionEvent;
+ import mx.events.CollectionEventKind;
+
+ import reflex.containers.IContainer;
+ import reflex.data.ISelection;
+
+ public class ListSelectionBehavior extends Behavior
+ {
+
+ private var _container:IContainer;
+ private var _selection:ISelection;
+
+ protected var _renderers:IList;
+ /*
+ [Bindable(event="containerChanged")]
+ [Binding(target="target.skin.container")]
+ public function get container():IContainer { return _container; }
+ public function set container(value:IContainer):void {
+ addContainer(value);
+ notify("container", _container, _container = value);
+ }
+ */
+
+ [Bindable(event="renderersChanged")]
+ [Binding(target="target.skin.container.renderers")]
+ public function get renderers():IList { return _renderers; }
+ public function set renderers(value:IList):void {
+ notify("renderers", _renderers, _renderers = value);
+ addItems(_renderers ? _renderers.toArray() : [], 0);
+ _renderers.addEventListener(CollectionEvent.COLLECTION_CHANGE, onChildrenChange, false, 0, true);
+ }
+
+ [Bindable(event="selectionChanged")]
+ [Binding(target="target.selection")]
+ public function get selection():ISelection{ return _selection; }
+ public function set selection(value:ISelection):void {
+ notify("selection", _selection, _selection= value);
+ }
+
+ public function ListSelectionBehavior(target:IEventDispatcher=null):void {
+ super(target);
+ }
+
+ private var _cancel:Boolean;
+ public function cancel():void {
+ _cancel = true;
+ //_container.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp, false, 0, true);
+ }
+ /*
+ //[EventListener(event="added", target="container")]
+ public function onRendererAdded(event:Event):void {
+ var renderer:Object = event.target;
+ if(renderer.parent == container || renderer.parent.parent == container) {
+ addRenderer(renderer as IEventDispatcher)
+ }
+ }
+
+ public function onRendererRemoved(event:Event):void {
+ var renderer:IEventDispatcher= event.target as IEventDispatcher
+ removeRenderer(renderer)
+ }
+
+ private function addContainer(container:IContainer):void {
+ if(container) {
+ var renderers:Array = container.g
+ var length:int = container.numChildren;
+ for(var i:int = 0; i < length; i++) {
+ var renderer:IEventDispatcher = container.getChildAt(i);
+ addRenderer(renderer);
+ }
+ container.addEventListener(Event.ADDED, onRendererAdded);
+ }
+ }
+
+ private function addRenderer(renderer:IEventDispatcher):void {
+ renderer.addEventListener(MouseEvent.CLICK, onRendererClick, false, 0, true);
+ renderers.push(renderer);
+ }
+
+ private function removeRenderer(renderer:IEventDispatcher):void {
+ renderer.removeEventListener(MouseEvent.CLICK, onRendererClick, false);
+ var index:int = renderers.indexOf(renderer);
+ renderers.splice(index, 1);
+ }
+ */
+
+ private function onChildrenChange(event:CollectionEvent):void
+ {
+ switch (event.kind) {
+ case CollectionEventKind.ADD :
+ addItems(event.items, event.location);
+ break;
+ case CollectionEventKind.REMOVE :
+ removeItems(event.items, event.oldLocation);
+ break;
+ /*case CollectionEventKind.REPLACE :
+ animationType = AnimationType.REPLACE;
+ helper.removeChild(display, event.items[1]);
+ //addChildAt(event.items[0], loc);
+ break;*/
+ case CollectionEventKind.RESET :
+ default:
+ removeItems(event.items, 0);
+ addItems(_renderers ? _renderers.toArray() : [], 0);
+ break;
+ }
+ }
+
+ private function addItems(items:Array, index:int):void {
+ var length:int = items ? items.length : 0;
+ for(var i:int = 0; i < length; i++) {
+ var item:IEventDispatcher = items[i];
+ item.addEventListener(MouseEvent.CLICK, onRendererClick, false, 0, true);
+ }
+ }
+
+ private function removeItems(items:Array, index:int):void {
+ for each (var item:IEventDispatcher in items) {
+ item.removeEventListener(MouseEvent.CLICK, onRendererClick, false);
+ }
+ }
+
+ private function onRendererClick(event:MouseEvent):void {
+ if(!_cancel) {
+ // just assuming IDataRenderer for now. this will need to be smarter later
+ var renderer:Object = event.currentTarget;
+ var item:Object = (event.currentTarget is IDataRenderer) ? (event.currentTarget as IDataRenderer).data : event.currentTarget;
+ if(event.ctrlKey) {
+ _selection.selectedItems.addItem(item);
+ } else {
+ _selection.selectedItem = item;
+ }
+
+ // making wild assumptions about the existence of selected properties here
+ for each(var r:Object in renderers) {
+ //r.selected = false;
+ }
+ //(renderer as Object).selected = !(renderer as Object).selected;
+ }
+ _cancel = false;
+ }
+
+ private function onMouseUp(event:MouseEvent):void {
+ //_container.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp, false);
+ //if(!_container.hitTestPoint(_container.stage.mouseX, _container.stage.mouseY)) {
+ // _cancel = false;
+ //}
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/behaviors/MovieClipSkinBehavior.as b/src/reflex/behaviors/MovieClipSkinBehavior.as
deleted file mode 100644
index 50fe70b4..00000000
--- a/src/reflex/behaviors/MovieClipSkinBehavior.as
+++ /dev/null
@@ -1,67 +0,0 @@
-package reflex.behaviors
-{
- import flash.display.DisplayObject;
- import flash.display.FrameLabel;
- import flash.display.MovieClip;
- import flash.events.IEventDispatcher;
-
- [SkinState("up")]
- [SkinState("over")]
- [SkinState("down")]
-
- public class MovieClipSkinBehavior extends Behavior
- {
-
- public static const UP:String = "up";
- public static const OVER:String = "over";
- public static const DOWN:String = "down";
-
- [Bindable]
- [Binding(target="target.currentState")]
- public var currentState:String = UP;
-
- [Bindable]
- [Binding(target="target.skin")]
- public var movieclip:MovieClip;
-
- public function MovieClipSkinBehavior(target:IEventDispatcher=null)
- {
- super(target);
- }
-
- // ====== Event Listeners ====== //
-
- [PropertyListener(target="movieclip")]
- public function onMovieClip(object:MovieClip):void
- {
- // trace(object);
- }
-
- [PropertyListener(target="currentState")]
- public function onState(object:String):void
- {
- if(movieclip) {
- gotoState(movieclip, object);
- }
- }
-
- // we'll update this for animated/play animations later
- private function gotoState(clip:MovieClip, state:String):void {
- var frames:Array = clip.currentLabels;
- for each(var label:FrameLabel in frames) {
- if(label.name == state) {
- clip.gotoAndStop(label.frame);
- }
- }
-
- var length:int = clip.numChildren; // recurse (for now)
- for(var i:int = 0; i < length; i++) {
- var child:DisplayObject = clip.getChildAt(i);
- if(child is MovieClip) {
- gotoState(child as MovieClip, state);
- }
- }
- }
-
- }
-}
\ No newline at end of file
diff --git a/src/reflex/behaviors/PopoutBehavior.as b/src/reflex/behaviors/PopoutBehavior.as
deleted file mode 100644
index e7ead8fd..00000000
--- a/src/reflex/behaviors/PopoutBehavior.as
+++ /dev/null
@@ -1,9 +0,0 @@
-package reflex.behaviors
-{
- public class PopoutBehavior
- {
- public function PopoutBehavior()
- {
- }
- }
-}
\ No newline at end of file
diff --git a/src/reflex/behaviors/ScrollerBehavior.as b/src/reflex/behaviors/ScrollerBehavior.as
new file mode 100644
index 00000000..970701d6
--- /dev/null
+++ b/src/reflex/behaviors/ScrollerBehavior.as
@@ -0,0 +1,63 @@
+package reflex.behaviors
+{
+ import flash.display.DisplayObject;
+ import flash.events.Event;
+ import flash.events.IEventDispatcher;
+
+ import reflex.data.IPosition;
+
+ public class ScrollerBehavior extends Behavior
+ {
+
+ private var _horizontalPosition:IPosition;
+ private var _verticalPosition:IPosition;
+ private var _container:DisplayObject;
+
+ [Bindable(event="horizontalPositionChange")]
+ [Binding(target="target.horizontalPosition")]
+ public function get horizontalPosition():IPosition { return _horizontalPosition; }
+ public function set horizontalPosition(value:IPosition):void {
+ notify("horizontalPosition", _horizontalPosition, _horizontalPosition = value);
+ }
+
+ [Bindable(event="verticalPositionChange")]
+ [Binding(target="target.verticalPosition")]
+ public function get verticalPosition():IPosition { return _verticalPosition; }
+ public function set verticalPosition(value:IPosition):void {
+ notify("verticalPosition", _verticalPosition, _verticalPosition = value);
+ }
+
+ [Bindable(event="containerChange")]
+ [Binding(target="target.skin.container")]
+ public function get container():DisplayObject { return _container; }
+ public function set container(value:DisplayObject):void {
+ notify("container", _container, _container = value);
+ }
+
+ public function ScrollerBehavior(target:IEventDispatcher=null)
+ {
+ super(target);
+ }
+
+ [EventListener(event="widthChange", target="container")]
+ [EventListener(event="valueChange", target="horizontalPosition")]
+ [EventListener(event="minimumChange", target="horizontalPosition")]
+ [EventListener(event="maximumChange", target="horizontalPosition")]
+ public function onHorizontalChange(event:Event):void {
+ var percent:Number = (horizontalPosition.value-horizontalPosition.minimum)/(horizontalPosition.maximum-horizontalPosition.minimum);
+ var potential:Number = (_container as Object).measured.width-(target as Object).width;
+ _container.x = Math.round(potential*percent*-1);
+ }
+
+ [EventListener(event="heightChange", target="container")]
+ [EventListener(event="valueChange", target="verticalPosition")]
+ [EventListener(event="minimumChange", target="verticalPosition")]
+ [EventListener(event="maximumChange", target="verticalPosition")]
+ public function onVerticalChange(event:Event):void {
+ var percent:Number = (verticalPosition.value-verticalPosition.minimum)/(verticalPosition.maximum-verticalPosition.minimum);
+ var potential:Number = (_container as Object).measured.height-(target as Object).height;
+ _container.y = Math.round(potential*percent*-1);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/behaviors/SelectBehavior.as b/src/reflex/behaviors/SelectBehavior.as
new file mode 100644
index 00000000..e8c5bf93
--- /dev/null
+++ b/src/reflex/behaviors/SelectBehavior.as
@@ -0,0 +1,38 @@
+package reflex.behaviors
+{
+ import flash.events.IEventDispatcher;
+ import flash.events.MouseEvent;
+
+
+ /**
+ * @description Adds selection toggling functionality to the target. When clicked, the target's selected property will be flipped.
+ * @alpha
+ */
+ public class SelectBehavior extends Behavior implements IBehavior
+ {
+
+ private var _selected:Boolean;
+
+ [Bindable(event="selectedChange")]
+ [Binding(target="target.selected")]
+ public function get selected():Boolean { return _selected; }
+ public function set selected(value:Boolean):void {
+ notify("selected", _selected, _selected = value);
+ }
+
+ public function SelectBehavior(target:IEventDispatcher= null)
+ {
+ super(target);
+ }
+
+ /**
+ * @private
+ */
+ [EventListener(event="click", target="target")]
+ public function onClick(event:MouseEvent):void
+ {
+ selected = !selected;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/behaviors/SelectableBehavior.as b/src/reflex/behaviors/SelectableBehavior.as
deleted file mode 100644
index 86b48248..00000000
--- a/src/reflex/behaviors/SelectableBehavior.as
+++ /dev/null
@@ -1,32 +0,0 @@
-package reflex.behaviors
-{
- import flash.display.InteractiveObject;
- import flash.events.MouseEvent;
-
- /**
- * @description Adds selection toggling functionality to the target. When clicked, the target's selected property will be flipped.
- * @alpha
- */
- public class SelectableBehavior extends Behavior implements IBehavior
- {
- [Bindable]
- [Binding(target="target.selected")]
- public var selected:Boolean;
-
- public function SelectableBehavior(target:InteractiveObject = null)
- {
- super(target);
- }
-
- /**
- * @private
- */
- [EventListener(type="click", target="target")]
- public function onClick(event:MouseEvent):void
- {
- selected = !selected;
- event.updateAfterEvent();
- }
-
- }
-}
\ No newline at end of file
diff --git a/src/reflex/behaviors/SlideBehavior.as b/src/reflex/behaviors/SlideBehavior.as
index 8371ce94..6150d0b0 100644
--- a/src/reflex/behaviors/SlideBehavior.as
+++ b/src/reflex/behaviors/SlideBehavior.as
@@ -1,175 +1,185 @@
package reflex.behaviors
{
- import flash.display.InteractiveObject;
+
import flash.events.Event;
import flash.events.IEventDispatcher;
- import flash.geom.Point;
-
- import flight.position.IPosition;
- import flight.position.Position;
+ import flash.events.MouseEvent;
- import reflex.events.ButtonEvent;
- import reflex.measurement.resolveHeight;
+ import reflex.data.IPagingPosition;
+ import reflex.data.IPosition;
public class SlideBehavior extends Behavior// extends StepBehavior
{
- [Bindable]
+ static public const HORIZONTAL:String = "horizontal";
+ static public const VERTICAL:String = "vertical";
+
+ private var _track:Object;
+ private var _thumb:Object;
+ private var _progress:Object;
+ private var _position:IPosition;
+ private var _mouseEnabled:Boolean = true;
+
+ public var page:Boolean = false;
+ public var layoutChildren:Boolean = true;
+ public var direction:String = HORIZONTAL;
+
+ [Bindable(event="trackChange")]
[Binding(target="target.skin.track")]
- public var track:InteractiveObject;
+ public function get track():Object { return _track; }
+ public function set track(value:Object):void {
+ notify("track", _track, _track = value);
+ }
- [Bindable]
+ [Bindable(event="thumbChange")]
[Binding(target="target.skin.thumb")]
- public var thumb:InteractiveObject;
+ public function get thumb():Object { return _thumb; }
+ public function set thumb(value:Object):void {
+ notify("thumb", _thumb, _thumb = value);
+ //(value as IEventDispatcher).addEventListener(MouseEvent.MOUSE_DOWN, onThumbDown, false, 0, true);
+ }
- [Bindable]
- [Binding(target="target.horizontal")]
- public var horizontal:Boolean = false;
+ [Bindable(event="progressChange")]
+ [Binding(target="target.skin.progress")]
+ public function get progress():Object { return _progress; }
+ public function set progress(value:Object):void {
+ notify("progress", _progress, _progress = value);
+ }
- [Bindable]
+ [Bindable(event="positionChange")]
[Binding(target="target.position")]
- public var position:IPosition = new Position(); // TODO: implement lazy instantiation of position
+ public function get position():IPosition { return _position; }
+ public function set position(value:IPosition):void {
+ notify("position", _position, _position = value);
+ }
- private var _percent:Number = 0;
- private var dragPercent:Number;
- private var dragPoint:Number;
- private var dragging:Boolean;
- private var forwardPress:Boolean;
+ [Bindable(event="mouseEnabledChange")]
+ public function get mouseEnabled():Boolean { return _mouseEnabled; }
+ public function set mouseEnabled(value:Boolean):void {
+ notify("mouseEnabled", _mouseEnabled, _mouseEnabled = value);
+ }
- public function SlideBehavior(target:InteractiveObject = null)
- {
+ public function SlideBehavior(target:IEventDispatcher = null, direction:String = "horizontal", page:Boolean = false) {
super(target);
+ this.direction = direction;
+ this.page = page;
+ //updateUILayout();
}
- [Bindable(event="percentChange")]
- public function get percent():Number
- {
- return _percent;
- }
+ // behavior
- override public function set target(value:IEventDispatcher):void
+ [EventListener(event="click", target="track")]
+ public function onTrackPress(event:MouseEvent):void
{
- super.target = value;
-
- if (target == null) {
- return;
- }
-
- track = getSkinPart("track");
- thumb = getSkinPart("thumb");
- if(track) { ButtonEvent.initialize(track); }
- if(thumb) { ButtonEvent.initialize(thumb); }
-
- if (track && track.width > track.height) {
- horizontal = true;
- }
- if(track && thumb) {
- updatePosition();
+ if(_mouseEnabled) {
+ var t:Object = target as Object;
+ if(page) {
+ if(direction == HORIZONTAL) {
+ pagePosition(event.localX - track.x, track.width);
+ } else if(direction == VERTICAL) {
+ pagePosition(event.localY - track.y, track.height);
+ }
+ } else {
+ if(direction == HORIZONTAL) {
+ jumpToPosition(event.localX - track.x, track.width);
+ } else if(direction == VERTICAL) {
+ jumpToPosition(event.localY - track.y, track.height);
+ }
+ }
+ updateUIPosition();
}
}
- [PropertyListener(target="position.percent")]
- public function onPosition(percent:Number):void
+
+ [EventListener(event="mouseDown", target="thumb")]
+ public function onThumbDown(event:MouseEvent):void
{
- if (thumb == null || track == null) {
- return;
- }
-
- if (!dragging) {
- _percent = position.percent;
- updatePosition();
- dispatchEvent(new Event("percentChange"));
+ if(_mouseEnabled) {
+ (target as Object).display.stage.addEventListener(Event.ENTER_FRAME, onEnterFrame, false, 0, true);
+ (target as Object).display.stage.addEventListener(MouseEvent.MOUSE_UP, onThumbUp, false, 0, true);
+ (target as Object).display.stage.addEventListener(Event.MOUSE_LEAVE, onThumbUp, false, 0, true);
+ //(target as Object).stage.addEventListener(MouseEvent.MOUSE_UP, onThumbUp, false, 0, true);
+ //(target as Object).stage.addEventListener(Event.MOUSE_LEAVE, onThumbUp, false, 0, true);
}
}
- [EventListener(type="press", target="track")]
- public function onTrackPress(event:ButtonEvent):void
- {
- var size:Number = horizontal ? track.width : track.height;
- forwardPress = (horizontal ? track.parent.mouseX - track.x : track.parent.mouseY - track.y) > (size * position.percent);
-
- if (forwardPress) {
- position.skipForward();
- } else {
- position.skipBackward();
- }
- event.updateAfterEvent();
+ private function onThumbUp(event:MouseEvent):void {
+ (target as Object).display.stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame, false);
+ (target as Object).display.stage.removeEventListener(MouseEvent.MOUSE_UP, onThumbUp, false);
+ (target as Object).display.stage.removeEventListener(Event.MOUSE_LEAVE, onThumbUp, false);
+ //(target as Object).stage.removeEventListener(MouseEvent.MOUSE_UP, onThumbUp, false);
+ //(target as Object).stage.removeEventListener(Event.MOUSE_LEAVE, onThumbUp, false);
}
- [EventListener(type="hold", target="track")]
- public function onTrackHold(event:ButtonEvent):void
- {
- var size:Number = horizontal ? track.width : track.height;
- var forwardHold:Boolean = (horizontal ? track.parent.mouseX - track.x : track.parent.mouseY - track.y) > (size * position.percent);
-
- if (forwardPress != forwardHold) {
- return;
- }
-
- if (forwardPress) {
- position.skipForward();
- } else {
- position.skipBackward();
+ private function onEnterFrame(event:Event):void {
+ var percent:Number = 0;
+ var t:Object = (target as Object).display;
+ if(direction == HORIZONTAL) {
+ percent = (t.mouseX - track.x)/track.width;
+ } else if(direction == VERTICAL) {
+ percent = (t.mouseY - track.y)/track.height;
}
- event.updateAfterEvent();
+ var value:Number = (position.maximum-position.minimum)*percent + position.minimum;
+ position.value = Math.max(position.minimum, Math.min(position.maximum, value));
+ updateUIPosition();
}
- [EventListener(type="press", target="thumb")]
- public function onThumbPress(event:ButtonEvent):void
- {
- dragging = true;
- dragPoint = horizontal ? thumb.parent.mouseX : thumb.parent.mouseY;
- dragPercent = _percent;
+
+ // skinpart positioning
+
+ //[CommitProperties(properties="position.min, position.max, position.position, position.pageSize")]
+ [EventListener(event="valueChange", target="position")]
+ public function onPositionChange(event:Event):void {
+ updateUIPosition();
}
- [EventListener(type="drag", target="thumb")]
- public function onThumbDrag(event:ButtonEvent):void
- {
- var mousePoint:Number = horizontal ? thumb.parent.mouseX : thumb.parent.mouseY;
- var size:Number = horizontal ? track.width - thumb.width : track.height - thumb.height;
- var delta:Number = (mousePoint - dragPoint) / size;
- _percent = dragPercent + delta;
- _percent = _percent <= 0 ? 0 : (_percent >= 1 ? 1 : _percent);
- position.percent = _percent;
- updatePosition();
- dispatchEvent(new Event("percentChange"));
-
- event.updateAfterEvent();
- }
-
- [EventListener(type="release", target="thumb")]
- [EventListener(type="releaseOutside", target="thumb")]
- public function onThumbRelease(event:ButtonEvent):void
- {
- dragging = false;
+ [EventListener(event="heightChange", target="target")]
+ public function onSizeChange(event:Event):void {
+ updateUILayout();
}
- [PropertyListener(target="target.width")]
- [PropertyListener(target="target.height")]
- public function onResize(size:Number):void
- {
- updatePosition();
+ private function pagePosition(v:Number, length:Number):void {
+ var scroll:IPagingPosition = position as IPagingPosition;
+ if(scroll) {
+ var center:Number = length/2;
+ if(v < center) {
+ scroll.value -= scroll.pageSize;
+ } else {
+ scroll.value += scroll.pageSize;
+ }
+ }
}
+ private function jumpToPosition(v:Number, length:Number):void {
+ var percent:Number = v/length;
+ position.value = (position.maximum-position.minimum)*percent + position.minimum;
+ }
- protected function updatePosition():void
- {
- if(track && thumb) {
- var p:Point = new Point();
-
- if (horizontal) {
- p.x = (track.width - thumb.width) * _percent + track.x;
- p = thumb.parent.globalToLocal( track.parent.localToGlobal(p) );
- thumb.x = Math.round(p.x);
- } else {
- var trackHeight:Number = reflex.measurement.resolveHeight(track);
- var thumbHeight:Number = reflex.measurement.resolveHeight(thumb);
- p.y = (trackHeight - thumbHeight) * _percent + track.y;
- p = thumb.parent.globalToLocal( track.parent.localToGlobal(p) );
- thumb.y = Math.round(p.y);
+ private function updateUIPosition():void {
+ var percent:Number = (position.value-position.minimum)/(position.maximum-position.minimum);
+ if(target) {
+ if(direction == HORIZONTAL) {
+ if(thumb && track) { thumb.x = track.x + (track.width-thumb.width) * percent; }
+ if(progress) { progress.width = track.width * percent; }
+ } else if(direction == VERTICAL) {
+ if(thumb && track) { thumb.y = track.y + (track.height-thumb.height) * percent; }
+ if(progress) { progress.height = track.height * percent; }
}
}
}
+ private function updateUILayout():void {
+ if(target) {
+ if(direction == HORIZONTAL) {
+ var h2:Number = (target as Object).height/2;
+ if(track) { track.y = h2 - track.height/2; }
+ if(thumb) { thumb.y = h2 - thumb.height/2; }
+ } else {
+ var w2:Number = (target as Object).width/2;
+ if(track) { track.x = w2 - track.width/2; }
+ if(thumb) { thumb.x = w2 - thumb.width/2; }
+ }
+ }
+ }
}
}
diff --git a/src/reflex/behaviors/StepBehavior.as b/src/reflex/behaviors/StepBehavior.as
index bda00449..2ac960c5 100644
--- a/src/reflex/behaviors/StepBehavior.as
+++ b/src/reflex/behaviors/StepBehavior.as
@@ -1,78 +1,58 @@
package reflex.behaviors
{
- import flash.display.InteractiveObject;
- import flash.display.MovieClip;
- import flash.events.IEventDispatcher;
- import flight.binding.Bind;
- import flight.position.IPosition;
- import flight.position.Position;
+ import flash.events.IEventDispatcher;
- import reflex.events.ButtonEvent;
+ import reflex.data.ISteppingPosition;
+
+ import flash.events.Event;
+
+ //import reflex.events.ButtonEvent;
public class StepBehavior extends Behavior
{
- public var fwdBehavior:ButtonBehavior;
- public var bwdBehavior:ButtonBehavior;
- [Bindable]
- public var fwdBtn:InteractiveObject;
- [Bindable]
- public var bwdBtn:InteractiveObject;
+ private var _incrementButton:Object;
+ private var _decrementButton:Object;
+ private var _position:ISteppingPosition;
[Bindable]
- [Binding(target="target.position")]
- public var position:IPosition = new Position(); // TODO: implement lazy instantiation of position
-
- public function StepBehavior(target:InteractiveObject = null)
- {
- super(target);
+ [Binding(target="target.skin.incrementButton")]
+ public function get incrementButton():Object { return _incrementButton; }
+ public function set incrementButton(value:Object):void {
+ notify("incrementButton", _incrementButton, _incrementButton = value);
}
- override public function set target(value:IEventDispatcher):void
- {
- super.target = value;
-
- if (target == null) {
- return;
- }
-
- fwdBtn = getSkinPart("fwdBtn");
- bwdBtn = getSkinPart("bwdBtn");
- fwdBehavior = new ButtonBehavior(fwdBtn);
- bwdBehavior = new ButtonBehavior(bwdBtn);
- if (fwdBtn is MovieClip) {
- Bind.addListener(this, onFwdStateChange, fwdBehavior, "state");
- }
- if (bwdBtn is MovieClip) {
- Bind.addListener(this, onBwdStateChange, bwdBehavior, "state");
- }
+ [Bindable]
+ [Binding(target="target.skin.decrementButton")]
+ public function get decrementButton():Object { return _decrementButton; }
+ public function set decrementButton(value:Object):void {
+ notify("decrementButton", _decrementButton, _decrementButton = value);
}
- [EventListener(type="press", target="fwdBtn")]
- [EventListener(type="hold", target="fwdBtn")]
- public function onFwdPress(event:ButtonEvent):void
- {
- position.forward();
- event.updateAfterEvent();
+ [Bindable]
+ [Binding(target="target.position")]
+ public function get position():ISteppingPosition { return _position; }
+ public function set position(value:ISteppingPosition):void {
+ notify("position", _position, _position = value);
}
- [EventListener(type="press", target="bwdBtn")]
- [EventListener(type="hold", target="bwdBtn")]
- public function onBwdPress(event:ButtonEvent):void
+ public function StepBehavior(target:IEventDispatcher = null)
{
- position.backward();
- event.updateAfterEvent();
+ super(target);
}
- protected function onFwdStateChange(state:String):void
+ [EventListener(event="click", target="incrementButton")]
+ public function onFwdPress(event:Event):void
{
- MovieClip(fwdBtn).gotoAndStop(state);
+ _position.value += _position.stepSize;
}
- protected function onBwdStateChange(state:String):void
+ [EventListener(event="click", target="decrementButton")]
+ public function onBwdPress(event:Event):void
{
- MovieClip(bwdBtn).gotoAndStop(state);
+ _position.value -= _position.stepSize;
}
+
}
}
\ No newline at end of file
diff --git a/src/reflex/behaviors/TextAreaBehavior.as b/src/reflex/behaviors/TextAreaBehavior.as
new file mode 100644
index 00000000..f744d344
--- /dev/null
+++ b/src/reflex/behaviors/TextAreaBehavior.as
@@ -0,0 +1,73 @@
+package reflex.behaviors
+{
+ import flash.events.Event;
+ import flash.events.IEventDispatcher;
+ import flash.text.TextField;
+
+ import reflex.data.IPosition;
+
+ public class TextAreaBehavior extends Behavior
+ {
+
+ private var _horizontalPosition:IPosition;
+ private var _verticalPosition:IPosition;
+ private var _textField:TextField;
+
+ [Bindable(event="horizontalPositionChange")]
+ [Binding(target="target.horizontalPosition")]
+ public function get horizontalPosition():IPosition { return _horizontalPosition; }
+ public function set horizontalPosition(value:IPosition):void {
+ notify("horizontalPosition", _horizontalPosition, _horizontalPosition = value);
+ }
+
+ [Bindable(event="verticalPositionChange")]
+ [Binding(target="target.verticalPosition")]
+ public function get verticalPosition():IPosition { return _verticalPosition; }
+ public function set verticalPosition(value:IPosition):void {
+ notify("verticalPosition", _verticalPosition, _verticalPosition = value);
+ }
+
+ [Bindable(event="textFieldChange")]
+ [Binding(target="target.skin.textField")]
+ public function get textField():TextField { return _textField; }
+ public function set textField(value:TextField):void {
+ notify("textField", _textField, _textField = value);
+ }
+
+ public function TextAreaBehavior(target:IEventDispatcher=null)
+ {
+ super(target);
+ }
+
+ [EventListener(event="valueChange", target="horizontalPosition")]
+ [EventListener(event="minimumChange", target="horizontalPosition")]
+ [EventListener(event="maximumChange", target="horizontalPosition")]
+ public function onHorizontalChange(event:Event):void {
+ var percent:Number = (horizontalPosition.value-horizontalPosition.minimum)/(horizontalPosition.maximum-horizontalPosition.minimum);
+ //_container.x = (_container.width-(target as Object).width)*percent*-1;
+ _textField.scrollH = (_textField.maxScrollV)*percent;
+ }
+
+ [EventListener(event="valueChange", target="verticalPosition")]
+ [EventListener(event="minimumChange", target="verticalPosition")]
+ [EventListener(event="maximumChange", target="verticalPosition")]
+ public function onVerticalChange(event:Event):void {
+ var percent:Number = (verticalPosition.value-verticalPosition.minimum)/(verticalPosition.maximum-verticalPosition.minimum);
+ //_container.y = (_container.height-(target as Object).height)*percent*-1;
+ _textField.scrollV = (_textField.maxScrollV)*percent;
+ }
+
+ [EventListener(event="scroll", target="textField")]
+ [EventListener(event="change", target="textField")]
+ [EventListener(event="widthChange", target="target")]
+ [EventListener(event="heightChange", target="target")]
+ public function onScrollChange(event:Event):void {
+ if(_textField && _textField.maxScrollV > 1) {
+ var percent:Number = _textField.scrollV/_textField.maxScrollV;
+ var range:Number = _verticalPosition.maximum - _verticalPosition.minimum;
+ _verticalPosition.value = _verticalPosition.minimum + range*percent;
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/behaviors/TouchScrollBehavior.as b/src/reflex/behaviors/TouchScrollBehavior.as
new file mode 100755
index 00000000..b330e743
--- /dev/null
+++ b/src/reflex/behaviors/TouchScrollBehavior.as
@@ -0,0 +1,112 @@
+package reflex.behaviors
+{
+ import flash.display.DisplayObject;
+ import flash.events.Event;
+ import flash.events.IEventDispatcher;
+ import flash.events.MouseEvent;
+ import flash.geom.Matrix3D;
+ import flash.geom.Point;
+ import flash.geom.Transform;
+ import flash.geom.Vector3D;
+
+ import reflex.behaviors.Behavior;
+ import reflex.data.IPosition;
+ import reflex.measurement.resolveHeight;
+ import reflex.measurement.resolveWidth;
+
+ //[HostComponent("flash.display.DisplayObject")]
+ public class TouchScrollBehavior extends Behavior
+ {
+
+ [Binding(target="target")]
+ public var hostComponent:DisplayObject;
+
+ private var point:Point;
+ private var speed:Point;
+ private var drag:Number = 0.95;
+
+ [Bindable]
+ public var round:Boolean = false;
+
+ [Bindable]
+ [Binding(target="target.verticalPosition")]
+ public var verticalPosition:IPosition;
+
+ [Bindable]
+ [Binding(target="target.horizontalPosition")]
+ public var horizontalPosition:IPosition;
+
+ [Bindable]
+ [Binding(target="target.skin.container")]
+ public var container:Object;
+
+ public var horizontalControl:Boolean = true;
+ public var verticalControl:Boolean = true;
+
+ public function TouchScrollBehavior(target:IEventDispatcher=null, horizontalControl:Boolean = true, verticalControl:Boolean = true)
+ {
+ super(target);
+ this.horizontalControl = horizontalControl;
+ this.verticalControl = verticalControl;
+ point = new Point();
+ speed = new Point();
+ }
+
+ [EventListener(event="mouseDown", target="target")]
+ public function onMouseDown(event:MouseEvent):void {
+ point.x = hostComponent.mouseX;
+ point.y = hostComponent.mouseY;
+ hostComponent.removeEventListener(Event.ENTER_FRAME, animation_enterFrameHandler, false);
+ hostComponent.addEventListener(Event.ENTER_FRAME, scrolling_enterFrameHandler, false, 0, true);
+ hostComponent.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp, false, 0, true);
+ drag = 0.95;
+ }
+
+ private function onMouseUp(event:MouseEvent):void {
+ speed.x = point.x - hostComponent.mouseX;
+ speed.y = point.y - hostComponent.mouseY;
+ point.x = hostComponent.mouseX;
+ point.y = hostComponent.mouseY;
+ //(target as DisplayObject).removeEventListener(MouseEvent.MOUSE_MOVE, scrolling_enterFrameHandler, false);
+ hostComponent.removeEventListener(Event.ENTER_FRAME, scrolling_enterFrameHandler, false);
+ hostComponent.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp, false);
+ hostComponent.addEventListener(Event.ENTER_FRAME, animation_enterFrameHandler, false, 0, true);
+ }
+
+ private function scrolling_enterFrameHandler(event:Event):void {
+ speed.x = point.x - hostComponent.mouseX;
+ speed.y = point.y - hostComponent.mouseY;
+ point.x = hostComponent.mouseX;
+ point.y = hostComponent.mouseY;
+ updatePositions();
+ }
+
+ private function animation_enterFrameHandler(event:Event):void {
+
+ updatePositions();
+ speed.x = speed.x * drag;
+ speed.y = speed.y * drag;
+ drag -= 0.005;
+ if(drag < 0.1) {
+ hostComponent.removeEventListener(Event.ENTER_FRAME, animation_enterFrameHandler, false);
+ }
+
+ }
+
+ private function updatePositions():void {
+ if(horizontalPosition && horizontalControl) {
+ var percentX:Number = speed.x/(container.measured.width-hostComponent.height);
+ var potentialX:Number = percentX*(horizontalPosition.maximum - horizontalPosition.minimum);
+ var px:Number = horizontalPosition.value + potentialX;
+ horizontalPosition.value = Math.max(horizontalPosition.minimum, Math.min(horizontalPosition.maximum, px));
+ }
+ if(verticalPosition && verticalControl) {
+ var percentY:Number = speed.y/(container.measured.height-hostComponent.height);
+ var potentialY:Number = percentY*(verticalPosition.maximum - verticalPosition.minimum);
+ var py:Number = verticalPosition.value + potentialY;
+ verticalPosition.value = Math.max(verticalPosition.minimum, Math.min(verticalPosition.maximum, py));
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/binding/Bind.as b/src/reflex/binding/Bind.as
new file mode 100644
index 00000000..10885571
--- /dev/null
+++ b/src/reflex/binding/Bind.as
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2009-2010 the original author or authors
+ *
+ * Permission is hereby granted to use, modify, and distribute this file
+ * in accordance with the terms of the license agreement accompanying it.
+ */
+
+package reflex.binding
+{
+ import flash.events.IEventDispatcher;
+ import flash.utils.Dictionary;
+
+ import mx.core.IMXMLObject;
+
+ /**
+ * The Bind class stands as the primary API for data binding, whether through Bind instances
+ * that represent a target property bound to some data source, or through it's static methods
+ * that allow global binding access. Bind's can be instantiated via ActionScript or MXML and
+ * simplify management of a single binding, allowing target and source to be changed anytime.
+ */
+ public class Bind implements IMXMLObject
+ {
+ public var twoWay:Boolean;
+ public var target:String;
+ public var source:String;
+
+ public function initialized(document:Object, id:String):void
+ {
+ if (target && source) {
+ Bind.addBinding(document, target, document, source, twoWay);
+ }
+ }
+
+
+ protected static var items:Dictionary = new Dictionary(true);
+ protected static var listeners:Dictionary = new Dictionary(true);
+ protected static var eventListeners:Dictionary = new Dictionary(true);
+ protected static var pool:Array = [];
+ protected static var holdInMemory:Function = updateListener;
+
+ /**
+ * Global utility method binding a target end point to a data source. Once a target is bound
+ * to the source, their values will synchronize immediately and on each subsequent change on
+ * the source. When enabling a two-way bind the source will also update to match the target.
+ *
+ * @param target A reference to the initial object in the target end point, the
+ * recipient of binding updates.
+ * @param targetPath A property or dot-separated property chain to be resolved in the
+ * target end point.
+ * @param source A reference to the initial object in the source end point, the
+ * initiator of binding updates.
+ * @param sourcePath A property or dot-separated property chain to be resolved in the
+ * source end point.
+ * @param twoWay When enabled, two-way binding updates both target and
+ * source upon changes to either.
+ *
+ * @return Considered successful if the binding has not already been established.
+ */
+ public static function addBinding(target:Object, targetPath:String, source:Object, sourcePath:String, twoWay:Boolean = false):Binding
+ {
+ return createBinding(target, targetPath, source, sourcePath, twoWay);
+ }
+
+ /**
+ * Global utility method destroying bindings made via addBinding. Once the binding
+ * is no longer in effect the properties will not be synchronized. However, source and target
+ * values will not be changed by removing the binding, so they will still match initially.
+ *
+ * @param target A reference to the initial object in the target end point, the
+ * recipient of binding updates.
+ * @param targetPath A property or dot-separated property chain to be resolved in the
+ * target end point.
+ * @param source A reference to the initial object in the source end point, the
+ * initiator of binding updates.
+ * @param sourcePath A property or dot-separated property chain to be resolved in the
+ * source end point.
+ *
+ * @return Considered successful if the specified binding was available.
+ */
+ public static function removeBinding(target:Object, targetPath:Object, source:Object, sourcePath:Object, twoWay:Boolean = false):Boolean
+ {
+ var binding:Binding = getBinding(target, targetPath, source, sourcePath, twoWay);
+ if (binding) {
+ releaseBinding(binding);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Removes all bindings, listeners, and bind event listeners that
+ * reference target object.
+ */
+ public static function removeAllBindings(target:Object):void
+ {
+ // bindings and listeners
+ var bindings:Array = items[target];
+ if (!bindings) {
+ return;
+ }
+ for each (var binding:Binding in bindings) {
+ releaseBinding(binding);
+ }
+ delete items[target];
+
+ // event listeners
+ delete eventListeners[target];
+ }
+
+ /**
+ * Global utility method binding an event listener to a data source. Once a listener is bound
+ * to the source, it will receive notification when source values change.
+ *
+ * @param listener An event listener object to be registered with the source binding.
+ * @param source A reference to the initial object in the source end point, the
+ * initiator of binding updates.
+ * @param sourcePath A property or dot-separated property chain to be resolved in the
+ * source end point.
+ * @param useWeakReference Determines whether the reference to the listener is strong or weak.
+ * A weak reference (the default) allows your listener to be garbage-
+ * collected. A strong reference does not.
+ */
+ public static function addListener(target:IEventDispatcher, listener:Function, source:Object, sourcePath:String):Binding
+ {
+ if (target) {
+ target.addEventListener("_", listener);
+ }
+ return createBinding(target, listener, source, sourcePath);
+ }
+
+ /**
+ * Global utility method removing an event listener from a source binding. Once the binding
+ * is no longer in effect the listener will not receive notification when source values change.
+ *
+ * @param listener An event listener object to be removed from the source binding.
+ * @param source A reference to the initial object in the source end point, the
+ * initiator of binding updates.
+ * @param sourcePath A property or dot-separated property chain to be resolved in the
+ * source end point.
+ */
+ public static function removeListener(target:IEventDispatcher, listener:Function, source:Object, sourcePath:String):Boolean
+ {
+ return removeBinding(target, listener, source, sourcePath);
+ }
+
+ // NOTE: weakReference specifies how the listener is added to the endpoint dispatcher, but the listener is held in memory by the binding
+ // TODO: refactor to allow the listener to be weakReference
+ public static function bindEventListener(type:String, listener:Function, source:Object, sourcePath:String, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = true):Binding
+ {
+ var binding:Binding = createBinding(source, updateListener, source, sourcePath);
+
+ // store the listener and other properties in a dictionary
+ var sourceListeners:Dictionary = eventListeners[source];
+ if (!sourceListeners) {
+ eventListeners[source] = sourceListeners = new Dictionary(true);
+ }
+
+ sourceListeners[binding] = [type, listener, useCapture, priority, useWeakReference];
+
+ // force update now since the first time couldn't register
+ if (binding.value) {
+ updateListener(binding, null, null, binding.value);
+ }
+ return binding;
+ }
+
+ public static function unbindEventListener(type:String, listener:Function, source:Object, sourcePath:String, useCapture:Boolean = false):Boolean
+ {
+ var binding:Binding = getBinding(source, updateListener, source, sourcePath);
+
+ if (!binding) {
+ return false;
+ }
+
+ var sourceListeners:Dictionary = eventListeners[source];
+ if (!sourceListeners) {
+ return false;
+ }
+
+ var args:Array = sourceListeners[binding];
+ if (!args) {
+ return false;
+ }
+
+ updateListener(binding, null, binding.value, null);
+ delete sourceListeners[binding];
+ releaseBinding(binding);
+ return true;
+ }
+
+ protected static function createBinding(target:Object, targetPath:Object, source:Object, sourcePath:Object, twoWay:Boolean = false):Binding
+ {
+ var binding:Binding = newBinding(target, targetPath, source, sourcePath, twoWay);
+
+ // store the binding in relation to the source and target so that
+ // they can be manually released.
+ var bindings:Array = items[target];
+ if (!bindings) {
+ items[target] = bindings = [];
+ }
+ bindings.push(binding);
+
+ // if target and source are the same no need to store it twice
+ if (target != source) {
+ bindings = items[source];
+ if (!bindings) {
+ items[source] = bindings = [];
+ }
+ }
+ return binding;
+ }
+
+ protected static function getBinding(target:Object, targetPath:Object, source:Object, sourcePath:Object, twoWay:Boolean = false):Binding
+ {
+ var bindings:Array = items[target] || items[source];
+ if (bindings) {
+ for each (var binding:Binding in bindings) {
+ if (binding.target == target && binding.source == source
+ && pathEquals(binding.targetPath, targetPath) && pathEquals(binding.sourcePath, sourcePath)
+ && binding.twoWay == twoWay) {
+ return binding;
+ }
+ }
+ }
+ return null;
+ }
+
+ protected static function updateListener(binding:Binding, item:Object, oldValue:*, newValue:*):void
+ {
+ if (!(binding.source in eventListeners && binding in eventListeners[binding.source])) {
+ return; // the first update happens before storing in listeners dict
+ }
+
+ var args:Array = eventListeners[binding.source][binding];
+ var dispatcher:IEventDispatcher;
+
+ dispatcher = oldValue as IEventDispatcher;
+ if (dispatcher != null) {
+ dispatcher.removeEventListener(args[0], args[1], args[2]);
+ }
+
+ dispatcher = newValue as IEventDispatcher;
+ if (dispatcher != null) {
+ dispatcher.addEventListener(args[0], args[1], args[2], args[3], args[4]);
+ }
+ }
+
+
+ protected static function releaseBinding(binding:Binding):void
+ {
+ var index:int;
+ var bindings:Array;
+ var source:Object, target:Object;
+ source = binding.source;
+ target = binding.target;
+
+ // remove from source
+ if (source) {
+ bindings = items[source];
+ if (bindings) {
+ index = bindings.indexOf(binding);
+ if (index != -1) {
+ bindings.splice(index, 1);
+ }
+ }
+ }
+
+ // remove from target
+ if (target && target != source) {
+ bindings = items[target];
+ if (bindings) {
+ index = bindings.indexOf(binding);
+ if (index != -1) {
+ bindings.splice(index, 1);
+ }
+ }
+ }
+
+ binding.release();
+ pool.push(binding);
+ }
+
+ protected static function newBinding(target:Object, targetPath:Object, source:Object, sourcePath:Object, twoWay:Boolean = false):Binding
+ {
+ if (pool.length) {
+ var binding:Binding = pool.pop();
+ binding.reset(target, targetPath, source, sourcePath, twoWay);
+ return binding;
+ } else {
+ return new Binding(target, targetPath, source, sourcePath, twoWay);
+ }
+ }
+
+ protected static function pathEquals(path1:Object, path2:Object):Boolean
+ {
+ // if they are not the same type
+ if (path1.constructor != path2.constructor) return false;
+
+ if (path1 is Array) {
+ var arr1:Array = path1 as Array, arr2:Array = path2 as Array;
+ if (arr1.length != arr2.length) return false;
+ var len:int = arr1.length;
+ for (var i:int = 0; i < len; i++) {
+ if (!pathEquals(arr1[i], arr2[i])) return false;
+ }
+ return true;
+ } else if (path1 is String) {
+ return path1 == path2;
+ } else if (path1 is Function) {
+ return path1 == path2;
+ } else {
+ for (var j:String in path1) {
+ if (path1[j] != path2[j]) return false;
+ }
+ return true;
+ }
+ }
+ }
+}
diff --git a/src/reflex/binding/Binding.as b/src/reflex/binding/Binding.as
new file mode 100644
index 00000000..72792e7f
--- /dev/null
+++ b/src/reflex/binding/Binding.as
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2009-2010 the original author or authors
+ *
+ * Permission is hereby granted to use, modify, and distribute this file
+ * in accordance with the terms of the license agreement accompanying it.
+ */
+
+package reflex.binding
+{
+ import flash.events.Event;
+ import flash.events.IEventDispatcher;
+ import flash.utils.Dictionary;
+
+ import mx.events.PropertyChangeEvent;
+
+ import reflex.metadata.Type;
+ import reflex.metadata.getClassName;
+ import reflex.metadata.getType;
+
+ [ExcludeClass]
+
+ /**
+ * Binding will bind two properties together. They can be shallow or deep
+ * and one way or two way.
+ */
+ public class Binding
+ {
+ protected static const SOURCE:String = "source";
+ protected static const TARGET:String = "target";
+
+ protected var sourceIndices:Dictionary = new Dictionary(true);
+ protected var targetIndices:Dictionary = new Dictionary(true);
+
+ protected var _sourcePath:Array;
+ protected var _targetPath:Array;
+
+ protected var _twoWay:Boolean;
+ protected var _value:*;
+
+ protected var sourceResolved:Boolean;
+ protected var targetResolved:Boolean;
+ protected var updating:Boolean;
+
+ protected var changeFunction:Function = propertyChange;
+
+ /**
+ *
+ */
+ public function Binding(target:Object = null, targetPath:Object = null, source:Object = null, sourcePath:Object = null, twoWay:Boolean = false)
+ {
+ if (target && targetPath && source && sourcePath) {
+ reset(target, targetPath, source, sourcePath, twoWay);
+ }
+ }
+
+ /**
+ * Indicates whether this binding has dropped either the source or the
+ * target. If either were dropped out of memory the binding is no longer
+ * valid and shoudl be released appropriatly.
+ */
+ public function get isInvalid():Boolean
+ {
+ var i:Object;
+ for (i in sourceIndices) {
+ for (i in targetIndices) return false;
+ }
+ return true;
+ }
+
+ public function get target():Object
+ {
+ for (var i:Object in targetIndices) {
+ if (targetIndices[i] == 0) return i;
+ }
+ return null;
+ }
+
+ public function get source():Object
+ {
+ for (var i:Object in sourceIndices) {
+ if (sourceIndices[i] == 0) return i;
+ }
+ return null;
+ }
+
+ public function get targetPath():String
+ {
+ return _targetPath.join(".");
+ }
+
+ public function get sourcePath():String
+ {
+ return _sourcePath.join(".");
+ }
+
+ public function get twoWay():Boolean
+ {
+ return _twoWay;
+ }
+
+ public function get value():*
+ {
+ return _value;
+ }
+
+ /**
+ *
+ */
+ public function release():void
+ {
+ unbindPath(SOURCE, 0);
+ unbindPath(TARGET, 0);
+ _sourcePath = null;
+ _targetPath = null;
+ _twoWay = false;
+ sourceResolved = false;
+ targetResolved = false;
+ _value = undefined;
+ }
+
+ public function reset(target:Object, targetPath:Object, source:Object, sourcePath:Object, twoWay:Boolean):void
+ {
+ release();
+ _twoWay = twoWay;
+
+ _sourcePath = makePath(sourcePath);
+ _targetPath = makePath(targetPath);
+
+ bindPath(TARGET, target, 0);
+ update(SOURCE, source, 0);
+ }
+
+ protected function update(type:String, item:Object, pathIndex:int = 0):void
+ {
+ var indices:Dictionary = this[type + "Indices"];
+ var path:Array = this["_" + type + "Path"];
+
+ var oldValue:* = _value;
+ _value = bindPath(type, item, pathIndex); // udpate full path
+
+ if (oldValue === _value) return;
+
+ updating = true;
+ var otherType:String = (type == SOURCE ? TARGET : SOURCE);
+ var resolved:Boolean = this[otherType + "Resolved"];
+ if (resolved) {
+ var otherPath:Array = this["_" + otherType + "Path"];
+ var otherItem:Object = getItem(otherType, otherPath.length - 1); // item + path.length
+ if (otherItem) {
+ var prop:Object = otherPath[otherPath.length - 1];
+ setProp(otherItem, prop, oldValue, _value);
+ }
+ }
+ updating = false;
+ }
+
+ /**
+ * Bind a path up starting from the given index.
+ */
+ protected function bindPath(type:String, item:Object, pathIndex:int):*
+ {
+ var indices:Dictionary = this[type + "Indices"];
+ var path:Array = this["_" + type + "Path"];
+ var onPropertyChange:Function = this[type + "ChangeHandler"];
+
+ unbindPath(type, pathIndex);
+
+ var resolved:Boolean;
+ var prop:Object;
+ var len:int = path.length;
+ for (pathIndex; pathIndex < len; pathIndex++) {
+
+ if (item == null) {
+ break;
+ }
+
+ indices[item] = pathIndex;
+
+ prop = path[pathIndex];
+ var propName:String = getPropName(prop);
+
+ if (propName && _twoWay || type == SOURCE || pathIndex < len-1) {
+ var changeEvents:Array = getBindingEvents(item, propName);
+ if (changeEvents == null || changeEvents[0] == "observable") {
+ //PropertyChange.addObserver(item, propName, null, propertyChange);
+ } else if (item is IEventDispatcher) {
+ for each (var changeEvent:String in changeEvents) {
+ IEventDispatcher(item).addEventListener(changeEvent, onPropertyChange, false, 100, true);
+ }
+ } else {
+ trace("Warning: Property '" + propName + "' is not bindable in " + getClassName(item) + ".");
+ }
+ }
+
+ try {
+ item = getProp(item, prop);
+ } catch (e:Error) {
+ item = null;
+ }
+ }
+
+ // if we've reached the end of the chain successfully (item + path - 1)
+ this[type + "Resolved"] = resolved = Boolean(pathIndex == len || item != null);
+ if (!resolved) {
+ return null;
+ }
+
+ return item;
+ }
+
+ /**
+ * Removes all event listeners from a certain point (index) in the path
+ * on up. A pathIndex of 0 will remove all listeners for the given type.
+ */
+ protected function unbindPath(type:String, pathIndex:int):void
+ {
+ var indices:Dictionary = this[type + "Indices"];
+ var path:Array = this["_" + type + "Path"];
+ var onPropertyChange:Function = this[type + "ChangeHandler"];
+
+ for (var item:* in indices) {
+ var index:int = indices[item];
+ if (index < pathIndex) {
+ continue;
+ }
+
+ var propName:String = getPropName(path[index]);
+ var changeEvents:Array = getBindingEvents(item, propName);
+ if (changeEvents == null || changeEvents[0] == "observable") {
+ //PropertyChange.removeObserver(item, propName, propertyChange);
+ } else if (item is IEventDispatcher) {
+ for each (var changeEvent:String in changeEvents) {
+ IEventDispatcher(item).removeEventListener(changeEvent, onPropertyChange);
+ }
+ }
+ delete indices[item];
+ }
+ }
+
+
+ protected function getItem(type:String, pathIndex:int = 0):Object
+ {
+ var indices:Dictionary = this[type + "Indices"];
+
+ for (var item:* in indices) {
+ if (indices[item] != pathIndex) {
+ continue;
+ }
+ return item;
+ }
+
+ return null;
+ }
+
+ protected function makePath(value:Object):Array
+ {
+ if (value is String) {
+ return String(value).split(".");
+ } else if (value is Array) {
+ return value as Array;
+ } else if (value != null) {
+ return [value];
+ }
+ return [];
+ }
+
+ protected function getPropName(prop:Object):String
+ {
+ if (prop is String) return prop as String;
+ if ("name" in prop) return prop.name;
+ return null;
+ }
+
+ protected function getProp(item:Object, prop:Object):*
+ {
+ var func:Function;
+
+ if ((func = prop as Function)
+ || ("getter" in prop && (func = prop.getter as Function))
+ || (prop in item && (func = item[prop] as Function)))
+ {
+ var params:Array = [item];
+ params.length = Math.min(func.length, 1);
+ return func.apply(null, params);
+ }
+
+ try {
+ return item[prop];
+ } catch (e:Error){}
+
+ return null;
+ }
+
+ protected function setProp(item:Object, prop:Object, oldValue:*, value:*):void
+ {
+ var func:Function;
+
+ if ((func = prop as Function)
+ || ("getter" in prop && (func = prop.getter as Function))
+ || (prop in item && (func = item[prop] as Function)))
+ {
+ var params:Array = [_value, oldValue, item, this];
+ params.length = Math.min(func.length, 4);
+ func.apply(null, params.reverse());
+ return;
+ }
+
+ try {
+ item[prop] = value;
+ } catch (e:Error){}
+ }
+
+ public function propertyChange(target:Object, name:String, oldValue:*, newValue:*):void
+ {
+ if (updating) return;
+ var pathIndex:int, prop:String;
+
+ if (target in sourceIndices) {
+ pathIndex = sourceIndices[target];
+ prop = _sourcePath[pathIndex];
+ if (prop == name) {
+ update(SOURCE, target[prop], pathIndex + 1);
+ return; // done
+ }
+ }
+
+ if (target in targetIndices) {
+ pathIndex = targetIndices[target];
+ prop = _targetPath[pathIndex];
+
+ if (prop == name) {
+ if (_twoWay) {
+ update(TARGET, target[prop], pathIndex + 1);
+ } else {
+ bindPath(TARGET, target[prop], pathIndex + 1);
+ if (sourceResolved && targetResolved) {
+ target = getItem(TARGET, _targetPath.length - 1);
+ prop = _targetPath[_targetPath.length - 1];
+ try {
+ target[prop] = _value;
+ } catch (e:Error) {}
+ }
+ }
+ }
+ }
+ }
+
+ protected function sourceChangeHandler(event:Event):void
+ {
+ if (updating) return;
+ var source:Object = event.target;
+ var pathIndex:int = sourceIndices[source];
+ var prop:String = _sourcePath[pathIndex];
+ if (event is PropertyChangeEvent && PropertyChangeEvent(event).property != prop) {
+ return;
+ }
+
+ update(SOURCE, source[prop], pathIndex + 1);
+ }
+
+ protected function targetChangeHandler(event:Event):void
+ {
+ if (updating) return;
+ var target:Object = event.target;
+ var pathIndex:int = targetIndices[target];
+ var prop:String = _targetPath[pathIndex];
+ if (event is PropertyChangeEvent && PropertyChangeEvent(event).property != prop) {
+ return;
+ }
+
+ if (_twoWay) {
+ update(TARGET, target[prop], pathIndex + 1);
+ } else {
+ bindPath(TARGET, target[prop], pathIndex + 1);
+ if (sourceResolved && targetResolved) {
+ target = getItem(TARGET, _targetPath.length - 1);
+ prop = _targetPath[_targetPath.length - 1];
+ try {
+ target[prop] = _value;
+ } catch (e:Error) {}
+ }
+ }
+ }
+
+
+ protected static var descCache:Dictionary = new Dictionary();
+
+ protected static function getBindingEvents(target:Object, property:String):Array
+ {
+ var bindings:Object = describeBindings(target);
+ return bindings[property];
+ }
+
+ protected static function describeBindings(value:Object):Object
+ {
+ if ( !(value is Class) ) {
+ value = getType(value);
+ }
+
+ if (descCache[value] == null) {
+ var desc:XMLList = Type.describeProperties(value, "Bindable");
+ var bindings:Object = descCache[value] = {};
+
+ for each (var prop:XML in desc) {
+ var property:String = prop.@name;
+ var changeEvents:Array = [];
+ var bindable:XMLList = prop.metadata.(@name == "Bindable");
+
+ for each (var bind:XML in bindable) {
+ if (bind.arg.(@value == "observable").length()) {
+ changeEvents.length = 0;
+ changeEvents.push("observable");
+ break;
+ } else {
+ var changeEvent:String = (bind.arg.(@key == "event").length() != 0) ?
+ bind.arg.(@key == "event").@value :
+ changeEvent = bind.arg.@value;
+
+ changeEvents.push(changeEvent);
+ }
+ }
+
+ bindings[property] = changeEvents;
+ }
+ }
+
+ return descCache[value];
+ }
+
+ }
+}
diff --git a/src/reflex/collections/SimpleCollection.as b/src/reflex/collections/SimpleCollection.as
new file mode 100644
index 00000000..2631658c
--- /dev/null
+++ b/src/reflex/collections/SimpleCollection.as
@@ -0,0 +1,96 @@
+package reflex.collections
+{
+ import flash.events.EventDispatcher;
+
+ import mx.collections.IList;
+ import mx.events.CollectionEvent;
+ import mx.events.CollectionEventKind;
+
+ [DefaultProperty("source")]
+ public class SimpleCollection extends EventDispatcher implements IList
+ {
+
+ private var _source:Array;
+
+ public function get source():Array { return _source; }
+ public function set source(value:Array):void {
+ _source = value;
+ var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE, false, false, CollectionEventKind.RESET, -1, -1, (_source == null) ? null : _source.concat());
+ dispatchEvent(event);
+ }
+
+ public function SimpleCollection(source:Array = null)
+ {
+ super();
+ if (source == null) {
+ source = [];
+ }
+ _source = source;
+ }
+
+ [Bindable(event="collectionChange")]
+ public function get length():int
+ {
+ return _source.length;
+ }
+
+ public function addItem(item:Object):void
+ {
+ var index:uint = _source.push(item)-1;
+ var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE, false, false, CollectionEventKind.ADD, index, -1, [item]);
+ dispatchEvent(event);
+ }
+
+ public function addItemAt(item:Object, index:int):void
+ {
+ _source.splice(index, 0, item);
+ var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE, false, false, CollectionEventKind.ADD, index, -1, [item]);
+ dispatchEvent(event);
+ }
+
+ public function getItemAt(index:int, prefetch:int=0):Object
+ {
+ // todo: implement prefetch
+ return _source[index];
+ }
+
+ public function getItemIndex(item:Object):int
+ {
+ return _source.indexOf(item);
+ }
+
+ public function itemUpdated(item:Object, property:Object=null, oldValue:Object=null, newValue:Object=null):void
+ {
+ // bah
+ }
+
+ public function removeAll():void
+ {
+ var items:Array = _source;
+ _source = [];
+ var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE, false, false, CollectionEventKind.RESET, -1, -1, items);
+ dispatchEvent(event);
+ }
+
+ public function removeItemAt(index:int):Object
+ {
+ var item:Object = _source.splice(index, 1);
+ var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE, false, false, CollectionEventKind.REMOVE, index, index, item as Array);
+ dispatchEvent(event);
+ return item[0];
+ }
+
+ public function setItemAt(item:Object, index:int):Object
+ {
+ var oldItem:Object = _source.splice(index, 1, item);
+ var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE, false, false, CollectionEventKind.REPLACE, index, index, [item]);
+ dispatchEvent(event);
+ return oldItem;
+ }
+
+ public function toArray():Array
+ {
+ return _source.concat();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/collections/convertIndexedObjectToArray.as b/src/reflex/collections/convertIndexedObjectToArray.as
new file mode 100644
index 00000000..59030823
--- /dev/null
+++ b/src/reflex/collections/convertIndexedObjectToArray.as
@@ -0,0 +1,14 @@
+package reflex.collections {
+
+ public function convertIndexedObjectToArray(indexedObject:Object):Array {
+ var array:Array = [];
+
+ var indexedObjectLength:int = indexedObject.length;
+
+ for (var i:int = 0; i < indexedObjectLength; i++ ) {
+ array[i] = indexedObject[i];
+ }
+
+ return array;
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/collections/convertToIList.as b/src/reflex/collections/convertToIList.as
new file mode 100644
index 00000000..8041c93a
--- /dev/null
+++ b/src/reflex/collections/convertToIList.as
@@ -0,0 +1,21 @@
+package reflex.collections {
+ import mx.collections.IList;
+
+ public function convertToIList(value:*):IList {
+ var ilist:IList;
+
+ if (value == null) {
+ ilist = null;
+ } else if (value is IList) {
+ ilist = value as IList;
+ } else if (value is Array) {
+ ilist = new SimpleCollection(value);
+ } else if (reflex.collections.isVector(value)) {
+ ilist = new SimpleCollection(reflex.collections.convertIndexedObjectToArray(value));
+ } else {
+ ilist = new SimpleCollection([value]);
+ }
+
+ return ilist;
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/collections/isVector.as b/src/reflex/collections/isVector.as
new file mode 100644
index 00000000..71f9eb33
--- /dev/null
+++ b/src/reflex/collections/isVector.as
@@ -0,0 +1,14 @@
+package reflex.collections {
+
+ public function isVector(value:*):Boolean {
+ var valueIsVector:Boolean = true;
+
+ try {
+ var vector:Vector.