//////////////////////////////////////////////////////////////////////////////// // // 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.binding { import mx.events.PropertyChangeEvent; [ExcludeClass] /** * @private * Bindability information for children (properties or methods) * of a given class, based on the describeType() structure for that class. */ public class BindabilityInfo { include "../core/Version.as"; //-------------------------------------------------------------------------- // // Class constants // //-------------------------------------------------------------------------- /** * Name of [Bindable] metadata. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static const BINDABLE:String = "Bindable"; /** * Name of [Managed] metadata. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static const MANAGED:String = "Managed"; /** * Name of [ChangeEvent] metadata. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static const CHANGE_EVENT:String = "ChangeEvent"; /** * Name of [NonCommittingChangeEvent] metadata. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static const NON_COMMITTING_CHANGE_EVENT:String = "NonCommittingChangeEvent"; /** * Name of describeType() element. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static const ACCESSOR:String = "accessor"; /** * Name of describeType() element. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static const METHOD:String = "method"; //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructor. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function BindabilityInfo(typeDescription:XML) { super(); this.typeDescription = typeDescription; } //-------------------------------------------------------------------------- // // Variables // //-------------------------------------------------------------------------- /** * @private */ private var typeDescription:XML; /** * @private * event name -> true */ private var classChangeEvents:Object; /** * @private * child name -> { event name -> true } */ private var childChangeEvents:Object = {}; //-------------------------------------------------------------------------- // // Variables // //-------------------------------------------------------------------------- /** * Object containing { eventName: true } for each change event * (class- or child-level) that applies to the specified child. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function getChangeEvents(childName:String):Object { var changeEvents:Object = childChangeEvents[childName]; if (!changeEvents) { // Seed with class-level events. changeEvents = copyProps(getClassChangeEvents(), {}); // Get child-specific events. var childDesc:XMLList = typeDescription.accessor.(@name == childName) + typeDescription.method.(@name == childName); var numChildren:int = childDesc.length(); if (numChildren == 0) { // we've been asked for events on an unknown property if (!typeDescription.@dynamic) { trace("warning: no describeType entry for '" + childName + "' on non-dynamic type '" + typeDescription.@name + "'"); } } else { if (numChildren > 1) { trace("warning: multiple describeType entries for '" + childName + "' on type '" + typeDescription.@name + "':\n" + childDesc); } addBindabilityEvents(childDesc.metadata, changeEvents); } childChangeEvents[childName] = changeEvents; } return changeEvents; } /** * @private * Build or return cached class change events object. */ private function getClassChangeEvents():Object { if (!classChangeEvents) { classChangeEvents = {}; addBindabilityEvents(typeDescription.metadata, classChangeEvents); // Class-level [Managed] means all properties // dispatch propertyChange. if (typeDescription.metadata.(@name == MANAGED).length() > 0) { classChangeEvents[PropertyChangeEvent.PROPERTY_CHANGE] = true; } } return classChangeEvents; } /** * @private */ private function addBindabilityEvents(metadata:XMLList, eventListObj:Object):void { addChangeEvents(metadata.(@name == BINDABLE), eventListObj, true); addChangeEvents(metadata.(@name == CHANGE_EVENT), eventListObj, true); addChangeEvents(metadata.(@name == NON_COMMITTING_CHANGE_EVENT), eventListObj, false); } /** * @private * Transfer change events from a list of change-event-carrying metadata * to an event list object. * Note: metadata's first arg value is assumed to be change event name. */ private function addChangeEvents(metadata:XMLList, eventListObj:Object, isCommit:Boolean):void { for each (var md:XML in metadata) { var arg:XMLList = md.arg; if (arg.length() > 0) { var eventName:String = arg[0].@value; eventListObj[eventName] = isCommit; } else { trace("warning: unconverted Bindable metadata in class '" + typeDescription.@name + "'"); } } } /** * @private * Copy properties from one object to another. */ private function copyProps(from:Object, to:Object):Object { for (var propName:String in from) { to[propName] = from[propName]; } return to; } } }