http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/77148f4a/frameworks/projects/MX/src/main/flex/mx/resources/ResourceManagerImpl.as ---------------------------------------------------------------------- diff --cc frameworks/projects/MX/src/main/flex/mx/resources/ResourceManagerImpl.as index ff6f91a,0000000..cfb5245 mode 100644,000000..100644 --- a/frameworks/projects/MX/src/main/flex/mx/resources/ResourceManagerImpl.as +++ b/frameworks/projects/MX/src/main/flex/mx/resources/ResourceManagerImpl.as @@@ -1,1441 -1,0 +1,1441 @@@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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.resources +{ + +import mx.events.FocusEvent; + +import org.apache.flex.core.CallLaterBead; +import org.apache.flex.events.Event; +import org.apache.flex.events.EventDispatcher; +import flex.system.DefinitionManager; +import flex.system.I18NManager; - COMPILE::AS3 ++COMPILE::SWF +{ + import flash.system.ApplicationDomain; +} +COMPILE::LATER +{ + import org.apache.flex.events.IEventDispatcher; + import flex.events.TimerEvent; + import flash.system.Capabilities; + import flash.system.SecurityDomain; + import flash.utils.Dictionary; + import mx.core.IFlexModuleFactory; + import mx.core.Singleton; + import mx.events.ModuleEvent; + import mx.events.ResourceEvent; + import mx.modules.IModuleInfo; + import mx.modules.ModuleManager; +} +import mx.core.mx_internal; +import mx.events.FlexEvent; +import mx.managers.SystemManagerGlobals; +import mx.utils.StringUtil; +import org.apache.flex.core.UIBase; + +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. + * + * <p>A single instance of this class manages all localized resources + * for a Flex application.</p> + * + * @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; + inFrame1 = true; + var topSM:UIBase = SystemManagerGlobals.topLevelSystemManagers[0] as UIBase; + if (topSM.getBeadByType(CallLaterBead) == null) + topSM.addBead(new CallLaterBead()); + var clb:CallLaterBead = topSM.getBeadByType(CallLaterBead) as CallLaterBead; + clb.callLater(enterFrameHandler, null, this); + } + } + + var info:Object = SystemManagerGlobals.info; + // Falcon injects this property and it is always false + // We ignore missing bundles because Falcon doesn't + // generate fallback bundles like MXMLC; + if (!inFrame1) + ignoreMissingBundles = info && info.hasOwnProperty("isMXMLC"); + + if (info) + processInfo(info, false); + + ignoreMissingBundles = info && info.hasOwnProperty("isMXMLC"); + + if (SystemManagerGlobals.topLevelSystemManagers.length) + SystemManagerGlobals.topLevelSystemManagers[0]. + addEventListener(FlexEvent.NEW_CHILD_APPLICATION, newChildApplicationHandler); + } + + //-------------------------------------------------------------------------- + // + // Variables + // + //-------------------------------------------------------------------------- + + /** + * @private + * + * Whether or ignoreMissingBundles was set in frame 1 + */ + private var inFrame1:Boolean = false; + + /** + * @private + * + * Whether or not to throw an error. + */ + private var ignoreMissingBundles:Boolean = false; + + /** + * @private + * + * The dictionary to hold all of the weak reference resource bundles. + */ + COMPILE::LATER + 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:DefinitionManager, + 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:DefinitionManager, + 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 a proxy + var proxy:ResourceBundleProxy = new ResourceBundleProxy(); + + proxy.bundleClass = bundleClass; + proxy.useWeakReference = useWeakReference; + + // 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. + proxy.locale = locale; + proxy.bundleName = bundleName; + + // Add that resource bundle instance to the ResourceManager. + resourceBundle = proxy; + 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"; + - COMPILE::AS3 ++ COMPILE::SWF + { + var applicationDomain:DefinitionManager = new DefinitionManager(info["currentDomain"]); + } + COMPILE::JS + { + var applicationDomain:DefinitionManager = new DefinitionManager(); + } + + var compiledResourceBundleNames:Array /* of String */ = + 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 + */ + COMPILE::LATER + 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 resourceEventDispatcher; + } + + /** + * @copy mx.resources.IResourceManager#unloadResourceModule() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + COMPILE::LATER + 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] = {}; + + COMPILE::LATER + { + 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]; + COMPILE::LATER + { + if (bundleObject is Dictionary) + { + if (ignoreWeakReferenceBundles) + return null; + + var localeBundleNameString:String = locale + bundleName; + for (var obj:Object in bundleObject) + { + if (bundleObject[obj] == localeBundleNameString) + { + if (obj is ResourceBundleProxy) + bundle = loadResourceBundleProxy(ResourceBundleProxy(obj)); + else + bundle = obj as IResourceBundle; + break; + } + } + } + } + /* else */if (bundleObject is ResourceBundleProxy) + { + bundle = loadResourceBundleProxy(ResourceBundleProxy(bundleObject)); + } + else + { + bundle = bundleObject as IResourceBundle; + } + + return bundle; + } + + private function loadResourceBundleProxy(proxy:ResourceBundleProxy):ResourceBundle { + var proxyClass:Class = proxy.bundleClass; + var resourceBundle:ResourceBundle = ResourceBundle(new proxyClass()); + resourceBundle._locale = proxy.locale; + resourceBundle._bundleName = proxy.bundleName; + + addResourceBundle(resourceBundle, proxy.useWeakReference); + + return resourceBundle; + } + + /** + * @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; + + COMPILE::LATER + { + if (bundleObject is Dictionary) + { + var localeBundleNameString:String = locale + bundleName; + for (var obj:Object in bundleObject) + { + if (bundleObject[obj] == localeBundleNameString) + { + if (obj is ResourceBundleProxy) + bundle = loadResourceBundleProxy(ResourceBundleProxy(obj)); + else + bundle = obj as IResourceBundle; + break; + } + } + } + } + /* else*/ if (bundleObject is ResourceBundleProxy) + { + bundle = loadResourceBundleProxy(ResourceBundleProxy(bundleObject)); + } + 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; + + if(!(resourceName in resourceBundle.content)) + 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; + - COMPILE::AS3 ++ COMPILE::SWF + { + var applicationDomain:DefinitionManager = + new DefinitionManager(ApplicationDomain.currentDomain); + } + COMPILE::JS + { + var applicationDomain:DefinitionManager = + new DefinitionManager(); + } + + 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 */ + { + return I18NManager.languages; + } + + /** + * @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():void + { + if (SystemManagerGlobals.topLevelSystemManagers.length) + { + if (SystemManagerGlobals.topLevelSystemManagers[0].currentFrame == 2) + { + inFrame1 = false; + } + else + { + var topSM:UIBase = SystemManagerGlobals.topLevelSystemManagers[0] as UIBase; + if (topSM.getBeadByType(CallLaterBead) == null) + topSM.addBead(new CallLaterBead()); + var clb:CallLaterBead = topSM.getBeadByType(CallLaterBead) as CallLaterBead; + clb.callLater(enterFrameHandler, null, this); + return; + } + } + + var info:Object = SystemManagerGlobals.info; + if (info) + processInfo(info, false); + } +} + +} + +COMPILE::LATER +{ +import flash.events.EventDispatcher; +import mx.events.ModuleEvent; +import mx.events.ResourceEvent; +import mx.modules.IModuleInfo; +import mx.resources.IResourceModule; +} +import mx.resources.IResourceBundle; + +//////////////////////////////////////////////////////////////////////////////// +// +// Helper class: ResourceModuleInfo +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * @private + */ +COMPILE::LATER +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 + */ +COMPILE::LATER +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); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Helper class: ResourceBundleProxy +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * @private + */ +class ResourceBundleProxy implements IResourceBundle +{ + public var bundleClass:Class; + public var useWeakReference:Boolean; + + private var _bundleName:String; + private var _locale:String; + + public function ResourceBundleProxy() + { + } + + public function get bundleName():String { + return _bundleName; + } + + public function set bundleName(value:String):void { + _bundleName = value; + } + + public function get content():Object { + return null; + } + + public function get locale():String { + return _locale; + } + + public function set locale(value:String):void { + _locale = value; + } +}
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/77148f4a/frameworks/projects/MX/src/main/flex/mx/states/AddChild.as ---------------------------------------------------------------------- diff --cc frameworks/projects/MX/src/main/flex/mx/states/AddChild.as index 68b17a6,0000000..07c9418 mode 100644,000000..100644 --- a/frameworks/projects/MX/src/main/flex/mx/states/AddChild.as +++ b/frameworks/projects/MX/src/main/flex/mx/states/AddChild.as @@@ -1,536 -1,0 +1,536 @@@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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.states +{ + - COMPILE::AS3 ++COMPILE::SWF +{ + import flash.display.DisplayObject; + import flash.display.DisplayObjectContainer; +} +COMPILE::JS +{ + import flex.display.DisplayObject; + import flex.display.DisplayObjectContainer; +} +import mx.core.ContainerCreationPolicy; +import mx.core.IDeferredInstance; +import mx.core.mx_internal; +import mx.core.UIComponent; +import mx.resources.IResourceManager; +import mx.resources.ResourceManager; + +use namespace mx_internal; + +[DefaultProperty("targetFactory")] + +[ResourceBundle("states")] + +/** + * The AddChild class adds a child display object, such as a component, + * to a container as part of a view state. + * You use this class in the <code>overrides</code> property of the State class. + * Use the <code>creationPolicy</code> property to specify to create the child + * at application startup or when you change to a view state. + * + * <p>The child does not dispatch the <code>creationComplete</code> event until + * it is added to a container. For example, the following code adds a + * Button control as part of a view state change:</p> + * + * <pre> + * <mx:AddChild relativeTo="{v1}"> + * <mx:Button id="b0" label="New Button"/> + * </mx:AddChild> </pre> + * + * <p>In the previous example, the Button control does not dispatch + * the <code>creationComplete</code> event until you change state and the + * Button control is added to a container. + * If the AddChild class defines both the Button and a container, such as a Canvas container, + * then the Button control dispatches the creationComplete event when it is created. + * For example, if the <code>creationPolicy</code> property is set to <code>all</code>, + * the Button control dispatches the event at application startup. + * If the <code>creationPolicy</code> property is set to <code>auto</code>, + * the Button control dispatches the event when you change to the view state. </p> + * + * @mxml + * + * <p>The <code><mx:AddChild></code> tag + * has the following attributes:</p> + * + * <pre> + * <mx:AddChild + * <b>Properties</b> + * target="null" + * targetFactory="null" + * creationPolicy="auto" + * position="lastChild" + * relativeTo="<i>parent of the State object</i>" + * /> + * </pre> + * + * @see mx.states.State + * @see mx.states.RemoveChild + * @see mx.states.Transition + * @see mx.effects.AddChildAction + * + * @includeExample examples/StatesExample.mxml + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public class AddChild extends OverrideBase +{ + include "../core/Version.as"; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @param relativeTo The component relative to which child is added. + * + * @param target The child object. + * All Flex components are subclasses of the DisplayObject class. + * + * @param position the location in the display list of the <code>target</code> + * relative to the <code>relativeTo</code> component. Must be one of the following: + * "firstChild", "lastChild", "before" or "after". + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function AddChild(relativeTo:UIComponent = null, + target:DisplayObject = null, + position:String = "lastChild") + { + super(); + + this.relativeTo = relativeTo; + this.target = target; + this.position = position; + } + + //-------------------------------------------------------------------------- + // + // Variables + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + mx_internal var added:Boolean = false; + + /** + * @private + */ + mx_internal var instanceCreated:Boolean = false; + + /** + * @private + * Used for accessing localized Error messages. + */ + private var resourceManager:IResourceManager = + ResourceManager.getInstance(); + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //------------------------------------ + // creationPolicy + //------------------------------------ + + /** + * @private + * Storage for the creationPolicy property. + */ + private var _creationPolicy:String = ContainerCreationPolicy.AUTO; + + [Inspectable(category="General")] + + /** + * The creation policy for this child. + * This property determines when the <code>targetFactory</code> will create + * the instance of the child. + * Flex uses this properthy only if you specify a <code>targetFactory</code> property. + * The following values are valid: + * + * <p></p> + * <table class="innertable"> + * <tr><th>Value</th><th>Meaning</th></tr> + * <tr><td><code>auto</code></td><td>(default)Create the instance the + * first time it is needed.</td></tr> + * <tr><td><code>all</code></td><td>Create the instance when the + * application started up.</td></tr> + * <tr><td><code>none</code></td><td>Do not automatically create the instance. + * You must call the <code>createInstance()</code> method to create + * the instance.</td></tr> + * </table> + * + * @default "auto" + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get creationPolicy():String + { + return _creationPolicy; + } + + /** + * @private + */ + public function set creationPolicy(value:String):void + { + _creationPolicy = value; + + if (_creationPolicy == ContainerCreationPolicy.ALL) + createInstance(); + } + + //------------------------------------ + // position + //------------------------------------ + + [Inspectable(category="General")] + + /** + * The position of the child in the display list, relative to the + * object specified by the <code>relativeTo</code> property. + * Valid values are <code>"before"</code>, <code>"after"</code>, + * <code>"firstChild"</code>, and <code>"lastChild"</code>. + * + * @default "lastChild" + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public var position:String; + + //------------------------------------ + // relativeTo + //------------------------------------ + + [Inspectable(category="General")] + + /** + * The object relative to which the child is added. This property is used + * in conjunction with the <code>position</code> property. + * This property is optional; if + * you omit it, Flex uses the immediate parent of the <code>State</code> + * object, that is, the component that has the <code>states</code> + * property, or <code><mx:states></code>tag that specifies the State + * object. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public var relativeTo:Object; + + //------------------------------------ + // target + //------------------------------------ + + /** + * @private + * Storage for the target property + */ + private var _target:DisplayObject; + + [Inspectable(category="General")] + + /** + * + * The child to be added. + * If you set this property, the child instance is created at app startup. + * Setting this property is equivalent to setting a <code>targetFactory</code> + * property with a <code>creationPolicy</code> of <code>"all"</code>. + * + * <p>Do not set this property if you set the <code>targetFactory</code> + * property.</p> + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get target():DisplayObject + { + if (!_target && creationPolicy != ContainerCreationPolicy.NONE) + createInstance(); + + return _target; + } + + /** + * @private + */ + public function set target(value:DisplayObject):void + { + _target = value; + } + + //------------------------------------ + // targetFactory + //------------------------------------ + + /** + * @private + * Storage for the targetFactory property. + */ + private var _targetFactory:IDeferredInstance; + + [Inspectable(category="General")] + + /** + * + * The factory that creates the child. You can specify either of the following items: + * <ul> + * <li>A factory class that implements the IDeferredInstance + * interface and creates the child instance or instances. + * </li> + * <li>A Flex component, (that is, any class that is a subclass + * of the UIComponent class), such as the Button contol. + * If you use a Flex component, the Flex compiler automatically + * wraps the component in a factory class. + * </li> + * </ul> + * + * <p>If you set this property, the child is instantiated at the time + * determined by the <code>creationPolicy</code> property.</p> + * + * <p>Do not set this property if you set the <code>target</code> + * property. + * This propety is the <code>AddChild</code> class default property. + * Setting this property with a <code>creationPolicy</code> of "all" + * is equivalent to setting a <code>target</code> property.</p> + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get targetFactory():IDeferredInstance + { + return _targetFactory; + } + + /** + * @private + */ + public function set targetFactory(value:IDeferredInstance):void + { + _targetFactory = value; + + if (creationPolicy == ContainerCreationPolicy.ALL) + createInstance(); + } + + //-------------------------------------------------------------------------- + // + // Methods + // + //-------------------------------------------------------------------------- + + /** + * Creates the child instance from the factory. + * You must use this method only if you specify a <code>targetFactory</code> + * property and a <code>creationPolicy</code> value of <code>"none"</code>. + * Flex automatically calls this method if the <code>creationPolicy</code> + * property value is <code>"auto"</code> or <code>"all"</code>. + * If you call this method multiple times, the child instance is + * created only on the first call. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function createInstance():void + { + if (!instanceCreated && !_target && targetFactory) + { + instanceCreated = true; + var instance:Object = targetFactory.getInstance(); + if (instance is DisplayObject) + _target = DisplayObject(instance); + } + } + + /** + * @inheritDoc + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + override public function initialize():void + { + if (creationPolicy == ContainerCreationPolicy.AUTO) + createInstance(); + } + + /** + * @inheritDoc + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + override public function apply(parent:UIComponent):void + { + var obj:* = getOverrideContext(relativeTo, parent); + + parentContext = parent; + added = false; + + // Early exit if child is null or not a valid container. + if (!target || !(obj is DisplayObjectContainer)) + { + if (relativeTo != null && !applied) + { + // Our destination context is unavailable so we attempt to register + // a listener on our parent document to detect when/if it becomes + // valid. + addContextListener(relativeTo); + } + applied = true; + return; + } + + applied = true; + relativeTo = obj; + + // Can't reparent. Must remove before adding. + if (target.parent) + { + var message:String = resourceManager.getString( + "states", "alreadyParented"); + throw new Error(message); + return; + } + + switch (position) + { + case "before": + { + obj.parent.addChildAt(target, + obj.parent.getChildIndex(obj)); + break; + } + + case "after": + { + obj.parent.addChildAt(target, + obj.parent.getChildIndex(obj) + 1); + break; + } + + case "firstChild": + { + obj.addChildAt(target, 0); + break; + } + + case "lastChild": + default: + { + obj.addChild(target); + break; + } + } + + added = true; + } + + /** + * @inheritDoc + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + override public function remove(parent:UIComponent):void + { + var obj:* = getOverrideContext(relativeTo, parent); + + if (!added || !(obj is DisplayObjectContainer)) + { + if (obj == null) + { + // It seems our override is no longer active, but we were never + // able to successfully apply ourselves, so remove our context + // listener if applicable. + removeContextListener(); + applied = false; + parentContext = null; + } + return; + } + + switch (position) + { + case "before": + case "after": + { + obj.parent.removeChild(target); + break; + } + + case "firstChild": + case "lastChild": + default: + { + if (obj == target.parent) + { + obj.removeChild(target); + } + break; + } + } + + // Clear our flags and override context. + added = false; + applied = false; + parentContext = null; + } +} + +}
