flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aha...@apache.org
Subject [10/37] git commit: [flex-asjs] [refs/heads/spark] - copy of many flex-sdk classes, modified to try to compile on top of the FlexJS base classes. A COMPILE::LATER flag is used to comment out features like multi-swf support and a few other features that
Date Sat, 13 Feb 2016 00:14:17 GMT
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/1f6418c4/frameworks/projects/MX/src/main/flex/mx/utils/MediaQueryParser.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/MX/src/main/flex/mx/utils/MediaQueryParser.as b/frameworks/projects/MX/src/main/flex/mx/utils/MediaQueryParser.as
new file mode 100644
index 0000000..6bc5801
--- /dev/null
+++ b/frameworks/projects/MX/src/main/flex/mx/utils/MediaQueryParser.as
@@ -0,0 +1,642 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.utils
+{
+import org.apache.flex.events.Event;
+import org.apache.flex.events.EventDispatcher;
+import org.apache.flex.core.UIBase;
+import flash.system.Capabilities;
+import mx.core.IFlexModuleFactory;
+import mx.core.mx_internal;
+import mx.managers.ISystemManager;
+import mx.managers.SystemManagerGlobals;
+import mx.styles.CSSDimension;
+import mx.styles.CSSOSVersion;
+import mx.styles.IStyleManager2;
+import mx.styles.StyleManager;
+
+use namespace mx_internal;
+
+[ExcludeClass]
+
+/**
+ *  @private
+ *  Parser for CSS Media Query syntax.  Not a full-fledged parser.
+ *  Doesn't report syntax errors, assumes you have your attributes
+ *  and identifiers spelled correctly, etc.
+ *  Media query parser now supports os-version selectors such as X, X.Y or X.Y.Z
+ *  Note that version with 2 or 3 parts must be  quoted
+Examples:
+ (os-platform: "ios") AND (min-os-version: 7)
+ (os-platform: "android") AND (min-os-version: "4.1.2")
+
+ non standard selectors:
+ -flex-device-diagonal
+ -flex-min-device-diagonal
+
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 10.2
+ *  @playerversion AIR 2.6
+ *  @productversion Flex 4.5
+ */ 
+public class MediaQueryParser  extends EventDispatcher
+{
+    /**
+     *  @private
+     *  Table of known media types
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10.2
+     *  @playerversion AIR 2.6
+     *  @productversion Flex 4.5
+     */
+     public static var platformMap:Object =
+     {
+         AND: "android",
+         IOS: "ios",
+         MAC: "macintosh",
+         WIN: "windows",
+         LNX: "linux",
+         QNX: "qnx"
+     }
+    
+     /**
+      *  @private
+      */
+     private static var _instance:MediaQueryParser;
+     
+     /**
+      *  Single shared instance of the parser
+      * 
+      *  @langversion 3.0
+      *  @playerversion Flash 10.2
+      *  @playerversion AIR 2.6
+      *  @productversion Flex 4.5
+      */
+     public static function get instance():MediaQueryParser
+     {
+         return _instance;
+     }
+     
+     /**
+      *  @private
+      */
+     public static function set instance(value:MediaQueryParser):void
+     {
+         if (!_instance)
+             _instance = value;
+     }
+     
+     /**
+     *  @private
+     *  Constructor
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10.2
+     *  @playerversion AIR 2.6
+     *  @productversion Flex 4.5
+     */
+    public function MediaQueryParser(moduleFactory:IFlexModuleFactory = null)
+    {        
+        applicationDpi = DensityUtil.getRuntimeDPI();
+        if (moduleFactory)
+        {
+            if (moduleFactory.info()["applicationDPI"] != null)
+                applicationDpi = moduleFactory.info()["applicationDPI"];
+            if (moduleFactory is ISystemManager){
+                sm = ISystemManager(moduleFactory);
+                if (sm.topOfDisplayList)
+                    sm.topOfDisplayList.addEventListener(UIBase.SIZE_CHANGED, stage_resizeHandler, false);
+            }
+        }
+        osPlatform = getPlatform();
+        osVersion = getOSVersion();
+        // compute device  DPI
+        deviceDPI = Capabilities.screenDPI;
+        // compute width, height and diagonal
+        computeDeviceDimensions( );
+
+    }
+
+    /**
+     *  Queries that were true
+     */
+    mx_internal var goodQueries:Object = {};
+    
+    /**
+     *  Queries that were false
+     */
+    mx_internal var badQueries:Object = {};
+
+    /**
+     * system manager for the MQP to compute device dimensions
+     */
+    private var sm: ISystemManager;
+
+    /** flags are set if device-width / device height are used in any media query.
+     * This is an optimization, so that   we know when it's necessary to regenerate styles
+     * */
+    private var usesDeviceWidth: Boolean = false ;
+    private var usesDeviceHeight: Boolean =false;
+    private var usesDeviceDiagonal: Boolean = false;
+    
+    /**
+     *  @private
+     *  Main entry point.
+     * 
+     *  @param expression A syntactically correct CSS Media Query
+     *  @returns true if valid for this media, false otherwise
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10.2
+     *  @playerversion AIR 2.6
+     *  @productversion Flex 4.5
+     */
+    public function parse(expression:String):Boolean
+    {
+        // remove whitespace
+        expression = StringUtil.trim(expression);
+       
+        // degenerate expressions
+        if (expression == "") return true;
+        
+        // known queries
+        if (goodQueries[expression]) return true;
+        if (badQueries[expression]) return false;
+                
+        // force to lower case cuz case-insensitive
+        var originalExpression:String = expression;
+        expression = expression.toLowerCase();
+        
+        //TODO : be smart and do not do a lowercase to do this test
+        if (expression == "all") return true;
+        
+        // get a list of queries.  If any pass then
+        // we're good
+        var mediaQueries:Array = expression.split(", ");
+        var n:int = mediaQueries.length;
+        for (var i:int = 0; i < n; i++)
+        {
+            var result:Boolean;
+            var mediaQuery:String = mediaQueries[i];
+            var notFlag:Boolean = false;
+            // eat only
+            if (mediaQuery.indexOf("only ") == 0)
+                mediaQuery = mediaQuery.substr(5);
+            // remember if this is a "not" expression
+            if (mediaQuery.indexOf("not ") == 0)
+            {
+                notFlag = true;
+                mediaQuery = mediaQuery.substr(4);
+            }
+            // get a list of the parts of the query.
+            // it should be media type, optionally
+            // followed by "and" followed by
+            // optional media feature expressions
+            var expressions:Array = tokenizeMediaQuery(mediaQuery);
+            var numExpressions:int = expressions.length;
+            if (expressions[0] == "all" || expressions[0] == type)
+            {
+                if (numExpressions == 1 && !notFlag)
+                {
+                    goodQueries[originalExpression] = true;
+                    return true;                                            
+                }
+                // bail if "and" and no media features (invalid query)
+                if (numExpressions == 2) return false;
+                // kick off the type and "and"
+                expressions.shift();
+                expressions.shift();
+                // see if the media features match
+                result = evalExpressions(expressions);
+                // early exit if it returned true;
+                if ((result && !notFlag) || (!result && notFlag))
+                {
+                    goodQueries[originalExpression] = true;
+                    return true;                    
+                }
+            }
+            // if we didn't match on media type and we have a notFlag
+            // then we match
+            else if (notFlag)
+            {
+                goodQueries[originalExpression] = true;                
+                return true;
+            }
+        }
+        badQueries[originalExpression] = true;
+        return false;
+    }
+    
+    // break up the expression into pieces
+    private function tokenizeMediaQuery(mediaQuery:String):Array
+    {        
+        var tokens:Array = [];
+        // if leading off with "(" then 
+        // "all and" is implied
+		var pos:int = mediaQuery.indexOf("(");
+        if (pos == 0)
+        {
+            tokens.push("all");
+            tokens.push("and");
+        }
+		else if (pos == -1)
+		{
+			// no parens means the whole thing should
+			// be the media type
+			return [ mediaQuery ];
+		}
+        
+        var parenLevel:int = 0;
+        var inComment:Boolean = false;
+        var n:int = mediaQuery.length;
+        var expression:Array = [];
+        // walk through each character looking for the pieces
+        for (var i:int = 0; i < n; i++)
+        {
+            var c:String = mediaQuery.charAt(i);
+            if (StringUtil.isWhitespace(c) && expression.length == 0)
+            {
+                // eat extra whitespace between tokens
+                continue;
+            }
+            else
+            {
+                // this piece should be the media type
+                if (c == '/' && i < n - 1 && mediaQuery.charAt(i + 1) == '*')
+                {
+                    inComment = true;
+                    i++;
+                    continue;
+                }
+                if (inComment)
+                {
+                    if (c == '*' && i < n - 1 && mediaQuery.charAt(i + 1) == '/')
+                    {
+                        inComment = false;
+                        i++;
+                    }
+                    continue;
+                }
+                else if (c == "(")  // Not sure whether these should be in the “else” here?
+                    parenLevel++;
+                else if (c == ")")
+                    parenLevel--;
+                else
+                {
+                    expression.push(c);
+                }
+                
+                // If we found whitespace and not in a paren, or just closed a paren,
+                // then that's the end of an expression
+                if (parenLevel == 0 && (StringUtil.isWhitespace(c) || (c == ")")))
+                {
+                    if (c != ")")
+                        expression.length--;
+                    tokens.push(expression.join(""));
+                    expression.length = 0; // reset
+                }
+                
+            }
+        }
+        return tokens;
+    }
+    
+    // take a media feature expression and evaluate it
+    private function evalExpressions(expressions:Array):Boolean
+    {
+        var n:int = expressions.length;
+        for (var i:int = 0; i < n; i++)
+        {
+            var expr:String = expressions[i];
+            // skip over "and"
+            if (expr == "and")
+                continue;
+            
+            // break into two pieces
+            var parts:Array = expr.split(":");
+            var key: String = parts[0];
+            var min:Boolean = false;
+            var max:Boolean = false;
+            var flex: Boolean = false;
+
+            // process custom  selectors
+            if (key.indexOf("-flex-") == 0){
+                 flex =true;
+                key = key.substr(6);
+            }
+
+            // look for min
+            if (key.indexOf("min-") == 0)
+            {
+                min = true;
+                key = key.substr(4);
+            }
+            // look for max
+            else if (key.indexOf("max-") == 0)
+            {
+                max = true;
+                key = key.substr(4);
+            }
+            // collapse hypens into camelcase ;
+            if (key.indexOf("-") > 0)
+                key = deHyphenate(key, flex);
+
+            if ( key == "deviceWidth")
+                 usesDeviceWidth = true;
+            else if (key  =="deviceHeight" )
+               usesDeviceHeight = true;
+            else if (key == "flexDeviceDiagonal")
+                usesDeviceDiagonal = true;
+
+            // if only one part, then it only matters that this property exists
+            if (parts.length == 1)
+            {
+                if (!(key in this))
+                    return false;
+            }
+            // if two parts, then make sure the property exists and value matches
+            if (parts.length == 2)
+            {
+                // if property doesn't exist, then bail
+                if (!(key in this))
+                    return false;
+                var value: Object = normalize(parts[1], this[key]) ;
+                var cmp: int = compareValues(this[key], value) ;
+                // handle min (we don't check if min is allowed for this property)
+                if (min)
+                {
+                   if (cmp < 0)
+                       return false;
+                }
+                // handle max (we don't check if min is allowed for this property)
+                else if (max)
+                {
+                    if (cmp > 0)
+                        return false;
+                }
+                // bail if the value doesn't match
+                else if (cmp != 0)
+                {
+                    return false;
+                }
+            }
+            
+        }
+        // all parts matched so return true
+        return true;
+    }
+    
+    // strip off  unit if currentValue is Number or int
+    //  now supports versions (X.Y.Z) and numbers with units
+    private function normalize(s:String, currentValue: Object ):Object
+    {
+        var index:int;
+        
+        // strip leading white space
+        if (s.charAt(0) == " ")
+            s = s.substr(1);
+        
+        // for the numbers we currently handle, we
+        // might find dpi or ppi on it, that we just strip off.
+        // We don't handle dpcm yet.
+        if (currentValue is Number)
+        {
+            index = s.indexOf("dpi");
+            if (index != -1)
+            {
+                s = s.substr(0, index);
+            }
+            return Number(s);
+        }
+        else if (currentValue is int)
+        {
+            return int(s);
+        }
+        // string or CSS value
+        // strip quotes of strings
+        if (s.indexOf('"') == 0) {
+            if (s.lastIndexOf('"') == s.length - 1)
+                s = s.substr(1, s.length - 2);
+            else
+                s = s.substr(1);
+        }
+        //  string , return
+         if (currentValue is String)
+        {
+             return s;
+        }
+        else if (currentValue is CSSOSVersion) {
+            return new CSSOSVersion(s) ;
+        }
+        else if (currentValue is CSSDimension) {
+              var matches: Array = s.match(/([\d\.]+)(in|cm|dp|pt|px|)$/);    // decimal number following by either units or no unit
+             if (matches!= null && matches.length == 3) {
+                 var unit: String =  matches[2];
+                 var refDPI: Number = unit == CSSDimension.UNIT_DP ? applicationDpi : deviceDPI ; // DPI use applicationDPI  for conversion
+                 return new CSSDimension(Number(matches[1]), refDPI,unit );
+             }
+             else {
+                 throw new Error("Unknown unit in css media query:" + s); //TODO NLS Error message
+                 return s;
+             }
+
+         }
+        return s;
+    }
+
+    /**  @private
+     * Compares current value with test values, using currentValue type to determine comparison function
+     *  accepts number, int, string and CSSOSVersion.
+     *  Will accept LexicalUnit in the future
+     *
+     * @param currentValue
+     * @param testValue
+     * @return   -1 if currentValue < testValue, 1 if currentValue > testValue and 0 if equal
+     */
+    private function compareValues ( currentValue: Object, testValue: Object): int
+    {
+        if (currentValue is CSSOSVersion)
+           return CSSOSVersion(currentValue).compareTo(CSSOSVersion(testValue))  ;
+        else if (currentValue is CSSDimension)
+            return CSSDimension(currentValue).compareTo(CSSDimension(testValue));
+        else // scalar compare operators
+           if ( currentValue == testValue)
+              return 0;
+           else if ( currentValue < testValue)
+             return -1;
+           else
+             return 1;
+    }
+
+    // collapse "-" to camelCase
+    private function deHyphenate(s:String, flex: Boolean):String
+    {
+        var i:int = s.indexOf("-");
+        var part: String;
+        var c: String;
+
+        while (i > 0)
+        {
+             part = s.substr(i + 1);
+            s = s.substr(0, i);
+            c = (part.charAt(0)).toUpperCase();
+            s += c + part.substr(1);
+            i = s.indexOf("-");
+        }
+        // if flex, camel case and prefix with flex
+        if (flex){
+            c = (s.charAt(0)).toUpperCase();
+            s = "flex" + c + s.substr(1);
+        }
+        return s;
+    }
+    
+    private function getPlatform():String
+    {
+        var s:String = Capabilities.version.substr(0, 3);
+        // if there is a friendly name, then use it
+        if (platformMap.hasOwnProperty(s))
+            return platformMap[s] as String;
+        
+        // otherwise match against the 3 characters.
+        // use lower case because match are case
+        // insensitive and we lower case the entire
+        // expression
+        return s.toLowerCase();
+    }
+
+    /** @private
+     * returns a CSSOSVersion suitable for MediaQueryParser for the current device operating system version.
+     * */
+    private function getOSVersion():CSSOSVersion {
+		return  new CSSOSVersion(Platform.osVersion) ;
+    }
+
+    /** @private recompute device dimension
+     *
+     * @return true if any dimension that is used in media queries has changed, and styles need to be regenerated
+     *   we ignore changes to deviceDiagonal on purpose, so that only changing
+     */
+    private function computeDeviceDimensions(): Boolean
+    {
+        if (sm) {
+            var w: Number = sm.topOfDisplayList.stageWidth;
+            var h: Number = sm.topOfDisplayList.stageHeight;
+            var diag: Number = Math.sqrt(w * w + h * h);
+
+           // we need to update styles if device-width is used and has changed or device-height is used and has changed
+            // for example after switching orientation or going fullscreen
+            // we ignore changes to device diagonal on purpose
+
+            var needToUpdateStyles: Boolean = (usesDeviceWidth && w != deviceWidth.pixelValue)     || (usesDeviceHeight && h != deviceHeight.pixelValue) ;
+
+            deviceWidth = new CSSDimension(w, deviceDPI);
+            deviceHeight = new CSSDimension(h, deviceDPI);
+            flexDeviceDiagonal = new CSSDimension(  diag, deviceDPI );
+
+           return needToUpdateStyles;
+        }
+        return false;
+    }
+
+    private function stage_resizeHandler(event: Event): void
+    {
+        if (computeDeviceDimensions())  {
+            // reinit query cache then reload styles
+            goodQueries = {};
+            badQueries = {};
+            reinitApplicationStyles();
+        }
+
+    }
+
+    private function reinitApplicationStyles( ):void {
+
+        var styleManager: IStyleManager2 = StyleManager.getStyleManager(sm);
+
+        styleManager.stylesRoot = null;
+        styleManager.initProtoChainRoots();
+
+        var sms: Array = SystemManagerGlobals.topLevelSystemManagers;
+        var n: int = sms.length;
+        var i: int;
+
+        // Type as Object to avoid dependency on SystemManager.
+        var sm: ISystemManager;
+        var cm: Object;
+
+            // Regenerate all the proto chains
+            // for all objects in the application.
+            for (i = 0; i < n; i++) {
+                sm = sms[i];
+                cm = sm.getImplementation("mx.managers::ISystemManagerChildManager");
+                cm.regenerateStyleCache(true);
+            }
+
+        for (i = 0; i < n; i++) {
+            sm = sms[i];
+            cm = sm.getImplementation("mx.managers::ISystemManagerChildManager");
+            cm.notifyStyleChangeInChildren(null, true);      // all styles
+        }
+    }
+
+    /* real device DPI, use for converting physical units */
+    private var deviceDPI: Number ;
+
+    // the type of the media
+    public var type:String = "screen";
+    
+    // the resolution of the media
+    public var applicationDpi:Number;
+    
+    // the platform of the media
+    public var osPlatform:String;
+
+    // the platform os version of the media
+    public var osVersion: CSSOSVersion;
+
+    /**
+     * Physical device width.
+     * matches "device-width" selector.
+     */
+    [Bindable]
+    public var deviceWidth: CSSDimension ;
+
+    /**
+     * Physical device height.
+     * matches "device-height" selector
+     */
+    [Bindable]
+    public var deviceHeight: CSSDimension;
+
+    /**
+     *  Physical device diagonal.
+     *  matches  "-flex-device-diagonal" selector
+     *  prefixed by "-flex" because it's not W3C standard
+     *
+     */
+    public var flexDeviceDiagonal: CSSDimension;
+
+}
+}
+
+

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/1f6418c4/frameworks/projects/MX/src/main/flex/mx/utils/NameUtil.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/MX/src/main/flex/mx/utils/NameUtil.as b/frameworks/projects/MX/src/main/flex/mx/utils/NameUtil.as
new file mode 100644
index 0000000..e8f0823
--- /dev/null
+++ b/frameworks/projects/MX/src/main/flex/mx/utils/NameUtil.as
@@ -0,0 +1,187 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.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 
+ *  the <code>NameUtil.createName()</code> 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 <code>displayObject</code> 
+     *  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 <code>"Button"</code>
+     *
+     *  <p>This string does not include the package name.
+     *  If you need the package name as well, call the
+     *  <code>getQualifiedClassName()</code> method in the flash.utils package.
+     *  It will return a string such as <code>"mx.controls::Button"</code>.</p>
+     *
+     *  @param object The object.
+     *
+     *  @return The name of the specified object's class.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function getUnqualifiedClassName(object:Object):String
+    {
+        var name:String;
+        if (object is String)
+            name = object as String;
+        else
+            name = getQualifiedClassName(object);
+
+        // If there is a package name, strip it off.
+        var index:int = name.indexOf("::");
+        if (index != -1)
+            name = name.substr(index + 2);
+
+        return name;
+    }
+}
+
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/1f6418c4/frameworks/projects/MX/src/main/flex/mx/utils/ObjectProxy.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/MX/src/main/flex/mx/utils/ObjectProxy.as b/frameworks/projects/MX/src/main/flex/mx/utils/ObjectProxy.as
new file mode 100644
index 0000000..03a8f51
--- /dev/null
+++ b/frameworks/projects/MX/src/main/flex/mx/utils/ObjectProxy.as
@@ -0,0 +1,825 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.utils
+{
+
+import flash.events.Event;
+import flash.events.EventDispatcher;
+import flash.utils.getQualifiedClassName;
+import flash.utils.IDataInput;
+import flash.utils.IDataOutput;
+import flash.utils.IExternalizable;
+import flash.utils.Proxy;
+import flash.utils.flash_proxy;
+import mx.core.IPropertyChangeNotifier;
+import mx.events.PropertyChangeEvent;
+import mx.events.PropertyChangeEventKind;
+
+use namespace flash_proxy;
+use namespace object_proxy;
+
+[Bindable("propertyChange")]
+[RemoteClass(alias="flex.messaging.io.ObjectProxy")]
+
+/**
+ *  This class provides the ability to track changes to an item
+ *  managed by this proxy.
+ *  Any number of objects can "listen" for changes on this
+ *  object, by using the <code>addEventListener()</code> method.
+ *
+ *  @example
+ *  <pre>
+ *  import mx.events.PropertyChangeEvent;
+ *  import mx.utils.ObjectUtil;
+ *  import mx.utils.ObjectProxy;
+ *  import mx.utils.StringUtil;
+ *
+ *  var a:Object = { name: "Tyler", age: 5, ssnum: "555-55-5555" };
+ *  var p:ObjectProxy = new ObjectProxy(a);
+ *  p.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, updateHandler);
+ *  p.name = "Jacey";
+ *  p.age = 2;
+ *  delete p.ssnum;
+ *
+ *  // handler function
+ *  function updateHandler(event:ChangeEvent):void
+ *  {
+ *      trace(StringUtil.substitute("updateHandler('{0}', {1}, {2}, {3}, '{4}')",
+ *                                     event.kind,
+ *                                     event.property,
+ *                                     event.oldValue,
+ *                                     event.newValue,
+ *                                     event.target.object_proxy::UUID));
+ *  }
+ * 
+ *  // The trace output appears as:
+ *  // updateHandler('opUpdate', name, Tyler, Jacey, '698AF8CB-B3D9-21A3-1AFFDGHT89075CD2')
+ *  // updateHandler('opUpdate', age, 5, 2, '698AF8CB-B3D9-21A3-1AFFDGHT89075CD2')
+ *  // updateHandler('opDelete', ssnum, 555-55-5555, null, '698AF8CB-B3D9-21A3-1AFFDGHT89075CD2')
+ *  </pre>
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public dynamic class ObjectProxy extends Proxy
+                                 implements IExternalizable,
+                                 IPropertyChangeNotifier
+{
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Initializes this proxy with the specified object, id and proxy depth.
+     * 
+     *  @param item Object to proxy.
+     *  If no item is specified, an anonymous object will be constructed
+     *  and assigned.
+     *
+     *  @param uid String containing the unique id
+     *  for this object instance.
+     *  Required for IPropertyChangeNotifier compliance as every object must 
+     *  provide a unique way of identifying it.
+     *  If no value is specified, a random id will be assigned.
+     *
+     *  @param proxyDepth An integer indicating how many levels in a complex
+     *  object graph should have a proxy created during property access.
+     *  The default is -1, meaning "proxy to infinite depth".
+     *  
+     *  @example
+     *
+     *  <pre>
+     *  import mx.events.PropertyChangeEvent;
+     *  import mx.utils.ObjectUtil;
+     *  import mx.utils.ObjectProxy;
+     *  import mx.utils.StringUtil;
+     *
+     *  var a:Object = { name: "Tyler", age: 5, ssnum: "555-55-5555" };
+     *  var p:ObjectProxy = new ObjectProxy(a);
+     *  p.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, updateHandler);
+     *  p.name = "Jacey";
+     *  p.age = 2;
+     *  delete p.ssnum;
+     *
+     *  // handler function
+     *  function updateHandler(event:PropertyChangeEvent):void
+     *  {
+     *      trace(StringUtil.substitute("updateHandler('{0}', {1}, {2}, {3}, '{4}')",
+     *                                     event.kind,
+     *                                     event.property,
+     *                                     event.oldValue,
+     *                                     event.newValue,
+     *                                     event.target.uid));
+     *  }
+     *
+     *  // trace output
+     *  updateHandler('opUpdate', name, Jacey, '698AF8CB-B3D9-21A3-1AFFDGHT89075CD2')
+     *  updateHandler('opUpdate', age, 2, '698AF8CB-B3D9-21A3-1AFFDGHT89075CD2')
+     *  updateHandler('opDelete', ssnum, null, '698AF8CB-B3D9-21A3-1AFFDGHT89075CD2')
+     *  </pre>
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function ObjectProxy(item:Object = null, uid:String = null,
+                                proxyDepth:int = -1)
+    {
+        super();
+
+        if (!item)
+            item = {};
+        _item = item;
+
+        _proxyLevel = proxyDepth;
+       
+        notifiers = {};
+
+        dispatcher = new EventDispatcher(this);
+
+        // If we got an id, use it.  Otherwise the UID is lazily
+        // created in the getter for UID.
+        if (uid)
+            _id = uid;
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Variables
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  A reference to the EventDispatcher for this proxy.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected var dispatcher:EventDispatcher;
+
+    /**
+     *  A hashmap of property change notifiers that this proxy is 
+     *  listening for changes from; the key of the map is the property name.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected var notifiers:Object;
+    
+    /**
+     *  Indicates what kind of proxy to create
+     *  when proxying complex properties.
+     *  Subclasses should assign this value appropriately.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected var proxyClass:Class = ObjectProxy;
+    
+    /**
+     *  Contains a list of all of the property names for the proxied object.
+     *  Descendants need to fill this list by overriding the
+     *  <code>setupPropertyList()</code> method.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected var propertyList:Array;
+    
+    /**
+     *  Indicates how deep proxying should be performed.
+     *  If -1 (default), always proxy; 
+     *  if this value is zero, no proxying will be performed.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    private var _proxyLevel:int;
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    //--------------------------------------------------------------------------
+
+    //----------------------------------
+    //  object
+    //----------------------------------
+
+    /**
+     *  Storage for the object property.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    private var _item:Object;
+
+    /**
+     *  The object being proxied.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    object_proxy function get object():Object
+    {
+        return _item;
+    }
+
+    //----------------------------------
+    //  type
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for the qualified type name.
+     */
+    private var _type:QName;
+
+    /**
+     *  The qualified type name associated with this object.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    object_proxy function get type():QName
+    {
+        return _type;
+    }
+
+    /**
+     *  @private
+     */
+    object_proxy function set type(value:QName):void
+    {
+        _type = value;
+    }
+
+    //----------------------------------
+    //  uid
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for the uid property.
+     */
+    private var _id:String;
+
+    /**
+     *  The unique identifier for this object.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get uid():String
+    {
+        if (_id === null)
+            _id = UIDUtil.createUID();
+            
+        return _id;
+    }
+
+    /**
+     *  @private
+     */
+    public function set uid(value:String):void
+    {
+        _id = value;
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Overridden methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Returns the specified property value of the proxied object.
+     *
+     *  @param name Typically a string containing the name of the property,
+     *  or possibly a QName where the property name is found by 
+     *  inspecting the <code>localName</code> property.
+     *
+     *  @return The value of the property.
+     *  In some instances this value may be an instance of 
+     *  <code>ObjectProxy</code>.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override flash_proxy function getProperty(name:*):*
+    {
+        // if we have a data proxy for this then
+        var result:*;
+
+        if (notifiers[name.toString()])
+            return notifiers[name];
+
+        result = _item[name];
+
+        if (result)
+        {
+            if (_proxyLevel == 0 || ObjectUtil.isSimple(result))
+            {
+                return result;
+            }
+            else
+            {
+                result = object_proxy::getComplexProperty(name, result);
+            } // if we are proxying
+        }
+
+        return result;
+    }
+
+    /**
+     *  Returns the value of the proxied object's method with the specified name.
+     *
+     *  @param name The name of the method being invoked.
+     *
+     *  @param rest An array specifying the arguments to the
+     *  called method.
+     *
+     *  @return The return value of the called method.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override flash_proxy function callProperty(name:*, ... rest):*
+    {
+        return _item[name].apply(_item, rest)
+    }
+
+    /**
+     *  Deletes the specified property on the proxied object and
+     *  sends notification of the delete to the handler.
+     * 
+     *  @param name Typically a string containing the name of the property,
+     *  or possibly a QName where the property name is found by 
+     *  inspecting the <code>localName</code> property.
+     *
+     *  @return A Boolean indicating if the property was deleted.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override flash_proxy function deleteProperty(name:*):Boolean
+    {
+        var notifier:IPropertyChangeNotifier = IPropertyChangeNotifier(notifiers[name]);
+        if (notifier)
+        {
+            notifier.removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE,
+                                         propertyChangeHandler);
+            delete notifiers[name];
+        }
+
+        var oldVal:* = _item[name];
+        var deleted:Boolean = delete _item[name]; 
+
+        if (dispatcher.hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE))
+        {
+            var event:PropertyChangeEvent = new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE);
+            event.kind = PropertyChangeEventKind.DELETE;
+            event.property = name;
+            event.oldValue = oldVal;
+            event.source = this;
+            dispatcher.dispatchEvent(event);
+        }
+
+        return deleted;
+    }
+
+    /**
+     *  @private
+     */
+    override flash_proxy function hasProperty(name:*):Boolean
+    {
+        return(name in _item);
+    }
+    
+    /**
+     *  @private
+     */
+    override flash_proxy function nextName(index:int):String
+    {
+        return propertyList[index -1];
+    }
+    
+    /**
+     *  @private
+     */
+    override flash_proxy function nextNameIndex(index:int):int
+    {
+        if (index == 0)
+        {
+            setupPropertyList();
+        }
+        
+        if (index < propertyList.length)
+        {
+            return index + 1;
+        }
+        else
+        {
+            return 0;
+        }
+    }
+    
+    /**
+     *  @private
+     */
+    override flash_proxy function nextValue(index:int):*
+    {
+        return _item[propertyList[index -1]];
+    }
+
+    /**
+     *  Updates the specified property on the proxied object
+     *  and sends notification of the update to the handler.
+     *
+     *  @param name Object containing the name of the property that
+     *  should be updated on the proxied object.
+     *
+     *  @param value Value that should be set on the proxied object.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override flash_proxy function setProperty(name:*, value:*):void
+    {
+        var oldVal:* = _item[name];
+        if (oldVal !== value)
+        {
+            // Update item.
+            _item[name] = value;
+
+            // Stop listening for events on old item if we currently are.
+            var notifier:IPropertyChangeNotifier =
+                IPropertyChangeNotifier(notifiers[name]);
+            if (notifier)
+            {
+                notifier.removeEventListener(
+                    PropertyChangeEvent.PROPERTY_CHANGE,
+                    propertyChangeHandler);
+                delete notifiers[name];
+            }
+
+            // Notify anyone interested.
+            if (dispatcher.hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE))
+            {
+                if (name is QName)
+                    name = QName(name).localName;
+                var event:PropertyChangeEvent =
+                    PropertyChangeEvent.createUpdateEvent(
+                        this, name.toString(), oldVal, value);
+                dispatcher.dispatchEvent(event);
+            } 
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  object_proxy methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Provides a place for subclasses to override how a complex property that
+     *  needs to be either proxied or daisy chained for event bubbling is managed.
+     * 
+     *  @param name Typically a string containing the name of the property,
+     *  or possibly a QName where the property name is found by 
+     *  inspecting the <code>localName</code> property.
+     *
+     *  @param value The property value.
+     *
+     *  @return The property value or an instance of <code>ObjectProxy</code>.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */  
+    object_proxy function getComplexProperty(name:*, value:*):*
+    {
+        if (value is IPropertyChangeNotifier)
+        {
+            value.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE,
+                                   propertyChangeHandler);
+            notifiers[name] = value;
+            return value;
+        }
+        
+        if (getQualifiedClassName(value) == "Object")
+        {
+            value = new proxyClass(_item[name], null,
+                _proxyLevel > 0 ? _proxyLevel - 1 : _proxyLevel);
+            value.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE,
+                                   propertyChangeHandler);
+            notifiers[name] = value;
+            return value;
+        }
+
+        return value;
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  IExternalizable Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Since Flex only uses ObjectProxy to wrap anonymous objects,
+     *  the server flex.messaging.io.ObjectProxy instance serializes itself
+     *  as a Map that will be returned as a plain ActionScript object. 
+     *  You can then set the object_proxy object property to this value.
+     *
+     *  @param input The source object from which the ObjectProxy is
+     *  deserialized. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function readExternal(input:IDataInput):void
+    {
+        var value:Object = input.readObject();
+        _item = value;
+    }
+
+    /**
+     *  Since Flex only serializes the inner ActionScript object that it wraps,
+     *  the server flex.messaging.io.ObjectProxy populates itself
+     *  with this anonymous object's contents and appears to the user
+     *  as a Map.
+     *
+     *  @param output The source object from which the ObjectProxy is
+     *  deserialized.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function writeExternal(output:IDataOutput):void
+    {
+        output.writeObject(_item);
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Registers an event listener object  
+     *  so that the listener receives notification of an event. 
+     *  For more information, including descriptions of the parameters see 
+     *  <code>addEventListener()</code> in the 
+     *  flash.events.EventDispatcher class.
+     *
+     *  @param type The type of event.
+     *  
+     *  @param listener The listener function that processes the event. This function must accept
+     *  an Event object as its only parameter and must return nothing.
+     *  
+     *  @param useCapture Determines whether the listener works in the capture phase or the 
+     *  target and bubbling phases. If <code>useCapture</code> is set to <code>true</code>, 
+     *  the listener processes the event only during the capture phase and not in the 
+     *  target or bubbling phase. If <code>useCapture</code> is <code>false</code>, the
+     *  listener processes the event only during the target or bubbling phase. To listen for
+     *  the event in all three phases, call <code>addEventListener</code> twice, once with 
+     *  <code>useCapture</code> set to <code>true</code>, then again with
+     *  <code>useCapture</code> set to <code>false</code>.
+     * 
+     *  @param priority The priority level of the event listener. 
+     * 
+     *  @param useWeakReference Determines whether the reference to the listener is strong or
+     *  weak. A strong reference (the default) prevents your listener from being garbage-collected.
+     *  A weak reference does not. 
+     *
+     *  @see flash.events.EventDispatcher#addEventListener()
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function addEventListener(type:String, listener:Function,
+                                     useCapture:Boolean = false,
+                                     priority:int = 0,
+                                     useWeakReference:Boolean = false):void
+    {
+        dispatcher.addEventListener(type, listener, useCapture,
+                                    priority, useWeakReference);
+    }
+
+    /**
+     *  Removes an event listener. 
+     *  If there is no matching listener registered with the EventDispatcher object, 
+     *  a call to this method has no effect.
+     *  For more information, see 
+     *  the flash.events.EventDispatcher class.
+     *  
+     *  @param type The type of event.
+     * 
+     *  @param listener The listener object to remove.
+     *
+     *  @param useCapture Specifies whether the listener was registered for the capture 
+     *  phase or the target and bubbling phases. If the listener was registered for both 
+     *  the capture phase and the target and bubbling phases, two calls to 
+     *  <code>removeEventListener()</code> are required to remove both, one call with 
+     *  <code>useCapture</code> 
+     *  set to <code>true</code>, and another call with <code>useCapture</code>
+     *  set to <code>false</code>.
+     *
+     *  @see flash.events.EventDispatcher#removeEventListener()
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function removeEventListener(type:String, listener:Function,
+                                        useCapture:Boolean = false):void
+    {
+        dispatcher.removeEventListener(type, listener, useCapture);
+    }
+
+    /**
+     *  Dispatches an event into the event flow. 
+     *  For more information, see
+     *  the flash.events.EventDispatcher class.
+     *  
+     *  @param event The Event object that is dispatched into the event flow. If the 
+     *  event is being redispatched, a clone of the event is created automatically. 
+     *  After an event is dispatched, its target property cannot be changed, so you 
+     *  must create a new copy of the event for redispatching to work.
+     *
+     *  @return Returns <code>true</code> if the event was successfully dispatched. 
+     *  A value 
+     *  of <code>false</code> indicates failure or that <code>preventDefault()</code>
+     *  was called on the event.
+     *
+     *  @see flash.events.EventDispatcher#dispatchEvent()
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function dispatchEvent(event:Event):Boolean
+    {
+        return dispatcher.dispatchEvent(event);
+    }
+    
+    /**
+     *  Checks whether there are any event listeners registered 
+     *  for a specific type of event. 
+     *  This allows you to determine where an object has altered handling 
+     *  of an event type in the event flow hierarchy. 
+     *  For more information, see
+     *  the flash.events.EventDispatcher class.
+     *
+     *  @param type The type of event
+     *
+     *  @return Returns <code>true</code> if a listener of the specified type is 
+     *  registered; <code>false</code> otherwise.
+     *
+     *  @see flash.events.EventDispatcher#hasEventListener()
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function hasEventListener(type:String):Boolean
+    {
+        return dispatcher.hasEventListener(type);
+    }
+    
+    /**
+     *  Checks whether an event listener is registered with this object 
+     *  or any of its ancestors for the specified event type. 
+     *  This method returns <code>true</code> if an event listener is triggered 
+     *  during any phase of the event flow when an event of the specified 
+     *  type is dispatched to this object or any of its descendants.
+     *  For more information, see the flash.events.EventDispatcher class.
+     *
+     *  @param type The type of event.
+     *
+     *  @return Returns <code>true</code> if a listener of the specified type will 
+     *  be triggered; <code>false</code> otherwise.
+     *
+     *  @see flash.events.EventDispatcher#willTrigger()
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function willTrigger(type:String):Boolean
+    {
+        return dispatcher.willTrigger(type);
+    }
+
+    /**
+     *  Called when a complex property is updated.
+     *
+     *  @param event An event object that has changed.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function propertyChangeHandler(event:PropertyChangeEvent):void
+    {
+        dispatcher.dispatchEvent(event);
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Protected Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  This method creates an array of all of the property names for the 
+     *  proxied object.
+     *  Descendants must override this method if they wish to add more 
+     *  properties to this list.
+     *  Be sure to call <code>super.setupPropertyList</code> before making any
+     *  changes to the <code>propertyList</code> property.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function setupPropertyList():void
+    {
+        if (getQualifiedClassName(_item) == "Object")
+        {
+            propertyList = [];
+            for (var prop:String in _item)
+                propertyList.push(prop);
+        }
+        else
+        {
+            propertyList = ObjectUtil.getClassInfo(_item, null, {includeReadOnly:true, uris:["*"]}).properties;
+        }
+    }
+}
+
+}


Mime
View raw message