//////////////////////////////////////////////////////////////////////////////// // // 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 flashx.textLayout.property { import flashx.textLayout.debug.assert; import flashx.textLayout.formats.FormatValue; import flashx.textLayout.tlf_internal; use namespace tlf_internal; [ExcludeClass] /** A property description with an Array value.@private */ public class ArrayProperty extends Property { private var _memberType:Class; public function ArrayProperty(nameValue:String, defaultValue:Array, inherited:Boolean, category:String, mType:Class) { _memberType = mType; CONFIG::debug { assert(_memberType.description != null,"Array member class must have description"); } // can defaultValue be INHERIT? CONFIG::debug { assert(checkArrayTypes(defaultValue),"Array has bad defaultValue"); } super(nameValue, defaultValue, inherited, category); } /** The type the members of the array are required to be. */ public function get memberType():Class { return _memberType; } protected function checkArrayTypes(val:Object):Boolean { if (val == null) return true; if (!(val is Array)) return false; if (_memberType == null) return true; for each (var obj:Object in (val as Array)) { if (!(obj is _memberType)) return false } return true; } /** @private */ public override function get defaultValue():Object { return super.defaultValue == null ? null : (super.defaultValue as Array).slice(); } /** @private */ public override function setHelper(currVal:*,newVal:*):* { if (newVal === null) newVal = undefined; if (newVal == undefined || newVal == FormatValue.INHERIT) return newVal; if (newVal is String) newVal = this.valueFromString(String(newVal)); if (!checkArrayTypes(newVal)) { Property.errorHandler(this,newVal); return currVal; } return (newVal as Array).slice(); } /** @private */ public override function concatInheritOnlyHelper(currVal:*,concatVal:*):* { return (inherited && currVal === undefined) || currVal == FormatValue.INHERIT ? ((concatVal is Array) ? (concatVal as Array).slice() : concatVal) : currVal; } /** @private */ public override function concatHelper(currVal:*,concatVal:*):* { if (inherited) return currVal === undefined || currVal == FormatValue.INHERIT ? ((concatVal is Array) ? (concatVal as Array).slice() : concatVal) : currVal; if (currVal === undefined) return defaultValue; return currVal == FormatValue.INHERIT ? ((concatVal is Array) ? (concatVal as Array).slice() : concatVal) : currVal; } /** @private */ public override function equalHelper(v1:*,v2:*):Boolean { if (_memberType != null) { var v1Array:Array = v1 as Array; var v2Array:Array = v2 as Array; if (v1Array && v2Array) { if (v1Array.length == v2Array.length) { var desc:Object = _memberType.description; for (var i:int=0; i < v1Array.length; ++i) { if (!Property.equalAllHelper(desc, v1[i], v2[i])) return false; } return true; } } } return v1 == v2; } /** @private */ public override function toXMLString(val:Object):String { if (val == FormatValue.INHERIT) return String(val); // TODO-7/7/2008-The XML format for array properties (as implemented below) // is appropriate for what it is currently used, but can be ambiguous. // For example, what if XML representations of contained elements contain the delimiters used here? // TODO: Check for description? var desc:Object = _memberType.description; var rslt:String = ""; var addSemi:Boolean = false; for each (var member:Object in val) { if (addSemi) rslt += "; " // export each element ',' separated var addComma:Boolean = false; for each (var prop:Property in desc) { var val:Object = member[prop.name]; if (val != null) { if (addComma) rslt += ", "; rslt += prop.name + ":" + prop.toXMLString(val); addComma = true; } } addSemi = true; } return rslt; } /** @private */ private function valueFromString(str:String):* { // TODO-7/7/2008-The XML format for array properties can be ambiguous. // See comment in toXMLString. if ((str == null) || (str == "")) return null; if (str == FormatValue.INHERIT) return str; var result:Array = new Array(); var desc:Object = _memberType.description; var attrsAll:Array = str.split('; '); for each (var attrs:String in attrsAll) { var obj:Object = new _memberType(); var attrsOne:Array = attrs.split(', '); for each (var attr:String in attrsOne) { var nameValArr:Array = attr.split(':'); var propName:String = nameValArr[0]; var propVal:String = nameValArr[1]; for each (var prop:Property in desc) { if (prop.name == propName) { obj[propName] = prop.setHelper(propVal,obj[propName]); break; } } } result.push(obj); } return result; } /** @private */ public override function hash(val:Object, seed:uint):uint { if (val == FormatValue.INHERIT) return UintProperty.doHash(inheritHashValue, seed); CONFIG::debug { assert(!(val is String),"ArrayProperty.has non inherit string"); } var hash:uint = seed; // TODO: Check for description? var desc:Object = _memberType.description; for each (var member:Object in val) { for each (var prop:Property in desc) { var val:Object = member[prop.name]; if (val != null) hash = prop.hash(val, hash); } } return hash; } } }