You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ah...@apache.org on 2014/09/03 02:17:51 UTC
[18/30] Radii8 code base as accepted by IP Clearance
http://git-wip-us.apache.org/repos/asf/flex-radii8/blob/f370bfcf/Radii8Library/src/com/flexcapacitor/utils/AndroidDocumentExporter.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/utils/AndroidDocumentExporter.as b/Radii8Library/src/com/flexcapacitor/utils/AndroidDocumentExporter.as
new file mode 100644
index 0000000..1b8df8c
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/utils/AndroidDocumentExporter.as
@@ -0,0 +1,518 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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 com.flexcapacitor.utils {
+ import com.flexcapacitor.model.IDocument;
+ import com.flexcapacitor.utils.supportClasses.ComponentDescription;
+
+ import mx.core.IVisualElement;
+
+ import spark.components.supportClasses.GroupBase;
+ import spark.layouts.HorizontalLayout;
+ import spark.layouts.VerticalLayout;
+
+ /**
+ * Exports a document to Android markup
+ * */
+ public class AndroidDocumentExporter extends DocumentExporter {
+
+ public function AndroidDocumentExporter() {
+
+ }
+
+ /**
+ * Last source code
+ * */
+ [Bindable]
+ public var sourceCode:String;
+
+ public var includePreviewCode:Boolean;
+
+ public var horizontalPositions:Array = ["x","left","right","horizontalCenter"];
+ public var verticalPositions:Array = ["y","top","bottom","verticalCenter"];
+ public var sizesPositions:Array = ["width","height"];
+
+
+ /**
+ * @inheritDoc
+ * */
+ public function exportXMLString(iDocument:IDocument, reference:Boolean = false, target:Object = null):String {
+ var XML1:XML;
+ //document = iDocument;
+ var application:Object = iDocument ? iDocument.instance : null;
+ var targetDescription:ComponentDescription;
+ var componentTree:ComponentDescription;
+ var output:String = "";
+ var xml:XML;
+
+ componentTree = iDocument.componentDescription;
+
+
+ // find target in display list and get it's code
+ targetDescription = DisplayObjectUtils.getTargetInComponentDisplayList(target, componentTree);
+
+
+ if (targetDescription) {
+
+ // see the top of this document on how to generate source code
+ getAppliedPropertiesFromHistory(iDocument, targetDescription);
+
+ if (!reference) {
+ //output = getAndroidOutputString(document.componentDescription);
+
+ var includePreviewCode:Boolean = true;
+
+ output = getAndroidOutputString(iDocument, targetDescription, true, "", includePreviewCode);
+ output = output + "\n";
+
+ try {
+ // don't use XML for Android output because it converts this:
+ // <div ></div>
+ // to this:
+ // <div />
+ // and that breaks the Android page
+
+ // we can still try it to make sure it's valid
+ xml = new XML(output); // check if valid
+
+ sourceCode = output;
+ // passing the raw string not the xml
+ //setTextareaCode(output);
+ }
+ catch (error:Error) {
+ // Error #1083: The prefix "s" for element "Group" is not bound.
+ // <s:Group x="93" y="128">
+ // <s:Button x="66" y="17"/>
+ //</s:Group>
+ sourceCode = output;
+ //setTextareaCode(output);
+ }
+ }
+ else {
+ XML1 = <document />;
+ XML1.@host = iDocument.host;
+ XML1.@id = iDocument.id;
+ XML1.@name = iDocument.name;
+ XML1.@uid = iDocument.uid;
+ XML1.@uri = iDocument.uri;
+ output = XML1.toXMLString();
+ }
+ }
+
+ return output;
+ }
+
+
+ /**
+ * Gets the formatted output from a component.
+ * Needs refactoring.
+ * */
+ public function getAndroidOutputString(iDocument:IDocument, component:ComponentDescription, addLineBreak:Boolean = false, tabs:String = "", includePreview:Boolean = false):String {
+ var property:Object = component.properties;
+ var name:String = component.name.toLowerCase();
+ var componentChild:ComponentDescription;
+ var styles:String = "position:absolute;";
+ var contentToken:String = "[child_content]";
+ var isHorizontalLayout:Boolean;
+ var isVerticalLayout:Boolean;
+ var childContent:String = "";
+ var wrapperTag:String = "";
+ var wrapperTagStyles:String = "";
+ var properties:String = "";
+ var output:String = "";
+ var type:String = "";
+ var value:*;
+ var index:int;
+ var numElements:int;
+ var gap:int;
+
+ // get layout positioning
+ if (component.parent && component.parent.instance is GroupBase) {
+
+ if (component.parent.instance.layout is HorizontalLayout) {
+ isHorizontalLayout = true;
+ index = GroupBase(component.parent.instance).getElementIndex(component.instance as IVisualElement);
+ numElements = GroupBase(component.parent.instance).numElements;
+ wrapperTagStyles += "display:inline;";
+ gap = HorizontalLayout(component.parent.instance.layout).gap - 4;
+
+ if (index<numElements-1 && numElements>1) {
+ wrapperTagStyles += "padding-right:" + gap + "px";
+ }
+
+ wrapperTag = "div";
+ }
+
+ else if (component.parent.instance.layout is VerticalLayout) {
+ isVerticalLayout = true;
+ styles = styles.replace("absolute", "relative");
+ index = GroupBase(component.parent.instance).getElementIndex(component.instance as IVisualElement);
+ numElements = GroupBase(component.parent.instance).numElements;
+ gap = VerticalLayout(component.parent.instance.layout).gap;
+
+ if (index<numElements-1 && numElements>1) {
+ wrapperTagStyles += "padding-bottom:" + gap + "px";
+ }
+
+ wrapperTag = "div";
+ }
+ }
+
+
+ // loop through assigned properties
+ for (var propertyName:String in property) {
+ value = property[propertyName];
+
+ if (value===undefined || value==null) {
+ continue;
+ }
+
+
+ // if horizontal or vertical layout do not add position
+ if (propertyName=="x" || propertyName=="left") {
+
+ if (!isHorizontalLayout && !isVerticalLayout) {
+ styles += "left:" + Object(property[propertyName]).toString() + "px;";
+ }
+ }
+ else if (propertyName=="y" || propertyName=="top") {
+
+ if (!isHorizontalLayout && !isVerticalLayout) {
+ styles += "top:" + Object(property[propertyName]).toString() + "px;";
+ }
+ }
+ else {
+ properties += propertyName + "=\"" + Object(property[propertyName]).toString() + "\"";
+ properties += " ";
+ }
+ }
+
+
+ if (name) {
+
+ // create code for element type
+ if (name=="application") {
+ name = "merge";
+ output += "<merge";
+ output += " xmlns:android=\"http://schemas.android.com/apk/res/android\"";
+ output += " xmlns:tools=\"http://schemas.android.com/tools\"";
+ output += ">";
+ output += contentToken;
+ output += "\n</merge>";
+
+ // container div
+ if (includePreview) {
+
+ }
+ else {
+ }
+ }
+
+ else if (name=="group") {
+ name = "RelativeLayout";
+ output = tabs + "<RelativeLayout";
+ output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+ output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+ output += ">";
+ output += contentToken;
+ output += "\n" + tabs + "</RelativeLayout>";
+ }
+
+
+ else if (name=="vgroup" || name=="hgroup") {
+ output = tabs + "<LinearLayout";
+
+ if (name=="hgroup") {
+ output += " android:orientation=\"horizontal\"";
+ }
+ else {
+ output += " android:orientation=\"vertical\"";
+ }
+ name = "LinearLayout";
+
+ output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+ output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+ output += ">";
+ output += contentToken;
+ output += "\n" + tabs + "</LinearLayout>";
+ }
+
+ else if (name=="button") {
+ /*<Button android:id="@+id/sign_in_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="@string/action_sign_in_register"
+ android:paddingLeft="32dp"
+ android:paddingRight="32dp"
+ android:layout_gravity="right" />*/
+ output = tabs;
+ output += "<Button";
+ output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+ output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+
+ /*if (component.parent.name=="group") {
+ output += " android:layout_marginLeft=\"" + getAndroidEquivalentPosition(component) + "\"";
+ output += " android:layout_marginTop=\"" + getAndroidEquivalentPosition(component, false) + "\"";
+ }
+ else {
+
+ }*/
+
+ output += " android:text=\"" + component.instance.label + "\"";
+ output += "/>";
+ }
+ else if (name=="checkbox") {
+ name = "CheckBox";
+ output = tabs;
+ output += "<CheckBox";
+ output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+ output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+ output += " android:text=\"" + component.instance.label + "\"/>";
+
+ //output += getWrapperTag(wrapperTag, true);
+ }
+ else if (name=="textinput") {
+ /*
+ <EditText
+ android:id="@+id/password"
+ android:singleLine="true"
+ android:maxLines="1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/prompt_password"
+ android:inputType="textPassword"
+ android:imeActionLabel="@string/action_sign_in_short"
+ android:imeActionId="@+id/login"
+ android:imeOptions="actionUnspecified" />*/
+ name = "EditText";
+ output = tabs;
+ output += "<EditText";
+ output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+ output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+ output += " android:singleLine=\"true\"";
+ output += " android:maxLines=\"1\"";
+ output += " android:fontFamily=\"" + component.instance.inheritingStyles.fontFamily + "\"";
+ output += " android:hint=\""+ component.instance.prompt +"\"";
+
+ if (component.instance.displayAsPassword) {
+ output += " android:inputType=\"textPassword\"";
+ }
+ else {
+ output += " android:inputType=\"text\"";
+ }
+
+ output += "/>";
+ }
+ else if (name=="label") {
+ /* <TextView
+ android:id="@+id/login_status_message"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:fontFamily="sans-serif-light"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:text="@string/login_progress_signing_in" />*/
+ name = "TextView";
+ output = tabs;
+ output += "<TextView";
+ output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+ output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+ output += " android:fontFamily=\"" + component.instance.inheritingStyles.fontFamily + "\"";
+ output += " android:text=\""+ component.instance.text+"\"";
+ output += "/>";
+ }
+ else if (name=="image") {
+ name = "ImageView";
+ output = tabs;
+ output += "<ImageView " + properties;
+ output += " android:layout_width=\"" + getAndroidEquivalentSize(component.instance as IVisualElement) + "\"";
+ output += " android:layout_height=\"" + getAndroidEquivalentSize(component.instance as IVisualElement, false) + "\"";
+ output += " android:src=\"@drawable/" + component.instance.source + "\"";
+ output += "/>";
+ }
+
+ else {
+ output = tabs;
+ output += "<!--<" + name.toLowerCase() + " " + properties;
+ output += properties ? " " : "";
+ output += "style=\"" + styles + "\"/>-->";
+ //output += getWrapperTag(wrapperTag, true);
+ }
+
+
+ // add children
+ if (component.children && component.children.length>0) {
+ //output += ">\n";
+
+ for (var i:int;i<component.children.length;i++) {
+ componentChild = component.children[i];
+ getAppliedPropertiesFromHistory(iDocument, componentChild);
+
+ if (i>0) {
+ childContent += "\n";
+ }
+
+ childContent += getAndroidOutputString(iDocument, componentChild, false, tabs + "\t");
+ }
+
+ output = output.replace(contentToken, "\n" + childContent);
+
+ }
+ else {
+ output = output.replace(contentToken, "\n");
+ }
+ }
+ else {
+ output = "";
+ }
+
+ return output;
+ }
+
+ /**
+ * Get Android equivalent size.
+ * Android has fill_parent, match_parent and wrap_content.
+ * It also has numeric value, like "55dp".
+ * */
+ public function getAndroidEquivalentSize(element:IVisualElement, width:Boolean = true):String {
+ var isPercent:Boolean;
+ var output:String;
+
+ // get width
+ if (width) {
+ isPercent = Boolean(element.percentWidth);
+
+ if (isPercent) {
+ if (element.percentWidth==100) {
+ output = "fill_parent";
+ }
+ else {
+ output = String(element.width) + "dp"; // absolute value
+ }
+ }
+ else {
+ if ("explicitWidth" in element && element.width==Object(element).explicitWidth) {
+ output = String(element.width) + "dp";
+ }
+ else {
+ output = "wrap_content";
+ }
+ }
+
+ return output;
+ }
+
+ // get height
+ isPercent = Boolean(element.percentHeight);
+
+
+ if (isPercent) {
+ if (element.percentHeight==100) {
+ output = "fill_parent";
+ }
+ else {
+ output = String(element.height) + "dp"; // absolute value
+ }
+ }
+ else {
+ if ("explicitHeight" in element && element.height==Object(element).percentHeight) {
+ output = String(element.height) + "dp";
+ }
+ else {
+ output = "wrap_content";
+ }
+ }
+
+ return output;
+ }
+
+ /**
+ * Get Android equivalent position
+ * */
+ public function getAndroidEquivalentPosition(componentDescription:ComponentDescription, x:Boolean = true):String {
+ var element:Object = componentDescription.instance;
+ var isPercent:Boolean;
+ var output:String;
+
+ // get width
+ if (x) {
+ isPercent = Boolean(element.percentWidth);
+
+
+ if (isPercent) {
+ if (element.percentWidth==100) {
+ output = "fill_parent";
+ }
+ else {
+ output = String(element.width) + "dp"; // absolute value
+ }
+ }
+ else {
+ if ("explicitWidth" in element && element.width==Object(element).explicitWidth) {
+ output = String(element.width) + "dp";
+ }
+ else {
+ output = "wrap_content";
+ }
+ }
+
+ return output;
+ }
+
+ // get height
+ isPercent = Boolean(element.percentHeight);
+
+
+ if (isPercent) {
+ if (element.percentHeight==100) {
+ output = "fill_parent";
+ }
+ else {
+ output = String(element.height) + "dp"; // absolute value
+ }
+ }
+ else {
+ if ("explicitHeight" in element && element.height==Object(element).percentHeight) {
+ output = String(element.height) + "dp";
+ }
+ else {
+ output = "wrap_content";
+ }
+ }
+
+ return output;
+ }
+
+ /**
+ * @inheritDoc
+ * */
+ public function exportXML(document:IDocument, reference:Boolean = false):XML {
+ return null;
+ }
+
+ /**
+ * @inheritDoc
+ * */
+ public function exportJSON(document:IDocument, reference:Boolean = false):JSON {
+ return null;
+ }
+
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-radii8/blob/f370bfcf/Radii8Library/src/com/flexcapacitor/utils/Base64.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/utils/Base64.as b/Radii8Library/src/com/flexcapacitor/utils/Base64.as
new file mode 100644
index 0000000..a84372c
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/utils/Base64.as
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012 Jean-Philippe Auclair
+ * Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+ * Base64 library for ActionScript 3.0.
+ * By: Jean-Philippe Auclair : http://jpauclair.net
+ * Based on article: http://jpauclair.net/2010/01/09/base64-optimized-as3-lib/
+ * Benchmark:
+ * This version: encode: 260ms decode: 255ms
+ * Blog version: encode: 322ms decode: 694ms
+ * as3Crypto encode: 6728ms decode: 4098ms
+ *
+ * Encode: com.sociodox.utils.Base64 is 25.8x faster than as3Crypto Base64
+ * Decode: com.sociodox.utils.Base64 is 16x faster than as3Crypto Base64
+ *
+ * Optimize & Profile any Flash content with TheMiner ( http://www.sociodox.com/theminer )
+ */
+package com.flexcapacitor.utils {
+
+ import flash.utils.ByteArray;
+
+ public class Base64
+ {
+ private static const _encodeChars:Vector.<int> = InitEncoreChar();
+ private static const _decodeChars:Vector.<int> = InitDecodeChar();
+
+ public static function encode(data:ByteArray):String
+ {
+ var out:ByteArray = new ByteArray();
+ //Presetting the length keep the memory smaller and optimize speed since there is no "grow" needed
+ out.length = (2 + data.length - ((data.length + 2) % 3)) * 4 / 3; //Preset length //1.6 to 1.5 ms
+ var i:int = 0;
+ var r:int = data.length % 3;
+ var len:int = data.length - r;
+ var c:uint; //read (3) character AND write (4) characters
+ var outPos:int = 0;
+ while (i < len)
+ {
+ //Read 3 Characters (8bit * 3 = 24 bits)
+ c = data[int(i++)] << 16 | data[int(i++)] << 8 | data[int(i++)];
+
+ out[int(outPos++)] = _encodeChars[int(c >>> 18)];
+ out[int(outPos++)] = _encodeChars[int(c >>> 12 & 0x3f)];
+ out[int(outPos++)] = _encodeChars[int(c >>> 6 & 0x3f)];
+ out[int(outPos++)] = _encodeChars[int(c & 0x3f)];
+ }
+
+ if (r == 1) //Need two "=" padding
+ {
+ //Read one char, write two chars, write padding
+ c = data[int(i)];
+
+ out[int(outPos++)] = _encodeChars[int(c >>> 2)];
+ out[int(outPos++)] = _encodeChars[int((c & 0x03) << 4)];
+ out[int(outPos++)] = 61;
+ out[int(outPos++)] = 61;
+ }
+ else if (r == 2) //Need one "=" padding
+ {
+ c = data[int(i++)] << 8 | data[int(i)];
+
+ out[int(outPos++)] = _encodeChars[int(c >>> 10)];
+ out[int(outPos++)] = _encodeChars[int(c >>> 4 & 0x3f)];
+ out[int(outPos++)] = _encodeChars[int((c & 0x0f) << 2)];
+ out[int(outPos++)] = 61;
+ }
+
+ return out.readUTFBytes(out.length);
+ }
+
+ public static function decode(str:String):ByteArray
+ {
+ var c1:int;
+ var c2:int;
+ var c3:int;
+ var c4:int;
+ var i:int = 0;
+ var len:int = str.length;
+
+ var byteString:ByteArray = new ByteArray();
+ byteString.writeUTFBytes(str);
+ var outPos:int = 0;
+ while (i < len)
+ {
+ //c1
+ c1 = _decodeChars[int(byteString[i++])];
+ if (c1 == -1)
+ break;
+
+ //c2
+ c2 = _decodeChars[int(byteString[i++])];
+ if (c2 == -1)
+ break;
+
+ byteString[int(outPos++)] = (c1 << 2) | ((c2 & 0x30) >> 4);
+
+ //c3
+ c3 = byteString[int(i++)];
+ if (c3 == 61)
+ {
+ byteString.length = outPos
+ return byteString;
+ }
+
+ c3 = _decodeChars[int(c3)];
+ if (c3 == -1)
+ break;
+
+ byteString[int(outPos++)] = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
+
+ //c4
+ c4 = byteString[int(i++)];
+ if (c4 == 61)
+ {
+ byteString.length = outPos
+ return byteString;
+ }
+
+ c4 = _decodeChars[int(c4)];
+ if (c4 == -1)
+ break;
+
+ byteString[int(outPos++)] = ((c3 & 0x03) << 6) | c4;
+ }
+ byteString.length = outPos
+ return byteString;
+ }
+
+ public static function InitEncoreChar():Vector.<int>
+ {
+ var encodeChars:Vector.<int> = new Vector.<int>(64, true);
+
+ // We could push the number directly
+ // but I think it's nice to see the characters (with no overhead on encode/decode)
+ var chars:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ for (var i:int = 0; i < 64; i++)
+ {
+ encodeChars[i] = chars.charCodeAt(i);
+ }
+
+ return encodeChars;
+ }
+
+ public static function InitDecodeChar():Vector.<int>
+ {
+
+ var decodeChars:Vector.<int> = new <int>[
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1];
+
+ return decodeChars;
+ }
+
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-radii8/blob/f370bfcf/Radii8Library/src/com/flexcapacitor/utils/ClassUtils.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/utils/ClassUtils.as b/Radii8Library/src/com/flexcapacitor/utils/ClassUtils.as
new file mode 100644
index 0000000..b3d7b8c
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/utils/ClassUtils.as
@@ -0,0 +1,716 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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 com.flexcapacitor.utils {
+ import com.flexcapacitor.events.InspectorEvent;
+ import com.flexcapacitor.graphics.LayoutLines;
+ import com.flexcapacitor.model.AccessorMetaData;
+ import com.flexcapacitor.model.MetaData;
+ import com.flexcapacitor.model.StyleMetaData;
+ import com.flexcapacitor.model.VisualElementVO;
+
+ import flash.desktop.Clipboard;
+ import flash.desktop.ClipboardFormats;
+ import flash.display.DisplayObject;
+ import flash.display.DisplayObjectContainer;
+ import flash.events.IEventDispatcher;
+ import flash.utils.describeType;
+ import flash.utils.getQualifiedClassName;
+ import flash.utils.getQualifiedSuperclassName;
+
+ import mx.collections.ArrayCollection;
+ import mx.collections.XMLListCollection;
+ import mx.core.IVisualElement;
+ import mx.core.IVisualElementContainer;
+ import mx.core.UIComponent;
+ import mx.managers.ISystemManager;
+ import mx.utils.DescribeTypeCache;
+ import mx.utils.DescribeTypeCacheRecord;
+ import mx.utils.NameUtil;
+ import mx.utils.ObjectUtil;
+
+ import avmplus.DescribeType;
+
+ public class ClassUtils {
+
+
+ public function ClassUtils() {
+
+
+ }
+
+ /**
+ * @copy NameUtil.getUnqualifiedClassName()
+ * */
+ public static function getClassName(element:Object):String {
+ var name:String = NameUtil.getUnqualifiedClassName(element);
+ return name;
+ }
+
+ /**
+ * Get unqualified class name of the target object. <br/>
+ *
+ * If target has the id of myImage and include class name is true then the result is
+ * "Image.myImage". If delimiter is "_" then the result is "Image_myImage".
+ * If includeClassName is false then the result is, "myImage".
+ * */
+ public static function getClassNameOrID(element:Object, includeClassName:Boolean = false, delimiter:String = "."):String {
+ var name:String = NameUtil.getUnqualifiedClassName(element);
+ var id:String = element && "id" in element ? element.id : null;
+
+ return !id ? name : includeClassName ? name + "." + id : id;
+ }
+
+ /**
+ * Get unqualified class name of the document of the target object
+ * returns null if element is not a UIComponent
+ * */
+ public static function getDocumentName(element:Object):String {
+ var name:String;
+ if (element is UIComponent) {
+ name = NameUtil.getUnqualifiedClassName(UIComponent(element).document);
+ }
+ return name;
+ }
+
+ /**
+ * Get the type of the value passed in
+ * */
+ public static function getValueType(value:*):String {
+ var type:String = getQualifiedClassName(value);
+
+ if (type=="int") {
+ if (typeof value=="number") {
+ type = "Number";
+ }
+ }
+
+ return type;
+ }
+
+ /**
+ * Get fully qualified package of an object minus the class name.
+ *
+ * For example, if fully qualified class name is "mx.components::Button" then
+ * this method returns "mx.components".
+ * */
+ public static function getPackageName(element:Object):String {
+ var name:String = flash.utils.getQualifiedClassName(element);
+ if (name && name.indexOf("::")) {
+ name = name.split("::")[0];
+ }
+
+ return name;
+ }
+
+ /**
+ * Get super class name of the target object
+ * */
+ public static function getSuperClassName(element:Object):String {
+ var name:String = flash.utils.getQualifiedSuperclassName(element);
+ if (name && name.indexOf("::")) {
+ name = name.split("::")[name.split("::").length-1]; // i'm sure theres a better way to do this
+ }
+
+ return name;
+ }
+
+ /**
+ * Get the package of the super class name of the target
+ * */
+ public static function getSuperClassPackage(element:Object):String {
+ var name:String = flash.utils.getQualifiedSuperclassName(element);
+ if (name && name.indexOf("::")) {
+ name = name.split("::")[0];
+ }
+
+ return name;
+ }
+
+
+ /**
+ * Gets the ID of the target object
+ *
+ * @param name if id is not available then if true then use name
+ * @param className if id is not available then if true use class name
+ *
+ * returns id or name or class name or null if no ID is specified
+ * */
+ public static function getIdentifierOrName(element:Object, name:Boolean = false, className:Boolean = false):String {
+
+ if (element && "id" in element && element.id) {
+ return element.id;
+ }
+ else if (element && name && "name" in element && element.name) {
+ return element.name;
+ }
+ else if (element && className) {
+ return getClassName(element);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get name of target object or null if not available
+ * */
+ public static function getName(element:Object):String {
+ var name:String;
+
+ if (element.hasOwnProperty("name") && element.name) {
+ name = element.name;
+ }
+
+ return name;
+ }
+
+ /**
+ * Get qualified class name of the target object.
+ * If normalize is true then replaces, "::" with ".";
+ *
+ * @copy flash.utils.getQualifiedClassName()
+ * */
+ public static function getQualifiedClassName(element:Object, normalize:Boolean = false):String {
+ var name:String = flash.utils.getQualifiedClassName(element);
+ if (normalize && name) {
+ name = name.replace("::", ".");
+ }
+ return name;
+ }
+
+ /**
+ * Checks if the source object is the same type as the target object.
+ * */
+ public static function isSameClassType(source:Object, target:Object):Boolean {
+ if (source==null && target!=null) {
+ return false;
+ }
+ if (target==null && source!=null) {
+ return false;
+ }
+
+ if (flash.utils.getQualifiedClassName(source) == flash.utils.getQualifiedClassName(target)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * With the given target it returns a regexp pattern to find the exact instance in MXML
+ * If isScript is true it attempts to returns a pattern to find the exact instance in AS3
+ * The MXML pattern will find the instance with that ID. If the instance doesn't have an ID it no worky.
+ * NOTE: Press CMD+SHIFT+F to and check regular expression in the Find in Files dialog
+ * */
+ public static function getRegExpSearchPattern(target:DisplayObject, isScript:Boolean = false):String {
+ var id:String = getIdentifierOrName(target);
+ var className:String = NameUtil.getUnqualifiedClassName(target);
+ var pattern:String;
+ var scriptPattern:String;
+
+ if (id == null) {
+ pattern = className + "(.*)";
+ }
+ else {
+ pattern = className + "(.*)id\\s?=\\s?[\"|']" + id + "[\"|']";
+ scriptPattern = id + ".addEventListener";
+ }
+
+
+ if (isScript) {
+ return scriptPattern;
+ }
+
+ return pattern;
+ }
+
+
+ /**
+ * Clears outline drawn around target display object
+ * */
+ public static function clearSelection(target:Object, systemManager:ISystemManager, remove:Boolean = false):void {
+ LayoutLines.getInstance().clear(target, systemManager, remove);
+ }
+
+ /**
+ * Draws outline around target display object
+ * */
+ public static function drawSelection(target:Object, systemManager:ISystemManager):void {
+ LayoutLines.getInstance().drawLines(target, systemManager);
+ }
+
+ /**
+ * Copy text to clipboard
+ * */
+ public static function copyToClipboard(text:String, format:String=ClipboardFormats.TEXT_FORMAT):void {
+ Clipboard.generalClipboard.setData(ClipboardFormats.TEXT_FORMAT, text);
+ }
+
+ /**
+ * Returns an array of display objects of type VisualElementVO
+ * Optionally returns elements
+ * */
+ public static function getElementChildrenArray(displayObject:DisplayObject, getElements:Boolean = false, getSkins:Boolean = true):ArrayCollection {
+ var displayObject:DisplayObject = DisplayObject(displayObject);
+ var displayObjectContainer:DisplayObjectContainer;
+
+ var visualElementContainer:IVisualElementContainer;
+ var visualElement:IVisualElement;
+
+ var visualElementVO:VisualElementVO = new VisualElementVO();
+
+ var children:ArrayCollection = new ArrayCollection();
+
+
+ // attempt to cast to a specific type and assign in the process
+ displayObjectContainer = displayObject as DisplayObjectContainer;
+ visualElementContainer = displayObject as IVisualElementContainer;
+ visualElement = displayObject as IVisualElement;
+
+
+ // gather all the display objects on the current display object
+ if (displayObjectContainer) {
+
+ for (var bb:int = 0; bb < displayObjectContainer.numChildren; bb++) {
+
+ // visualElementVO = createDisplayObjectVO(displayObjectContainer.getChildAt(bb));
+ visualElementVO = VisualElementVO.unmarshall(displayObjectContainer.getChildAt(bb));
+ children.addItem(visualElementVO);
+ }
+ }
+
+ if (visualElementContainer && getElements) {
+
+ for (var cc:int = 0; cc < visualElementContainer.numElements; cc++) {
+ //visualElementVO = createDisplayObjectVO(displayObjectContainer.getChildAt(cc));
+ visualElementVO = VisualElementVO.unmarshall(DisplayObject(visualElementContainer.getElementAt(cc)));
+ children.addItem(visualElementVO);
+ }
+ }
+
+ return children;
+ }
+
+ /**
+ * Get ancestors of target
+ *
+ * @param target
+ * @param collection
+ * @param ancestors
+ * @return
+ */
+ public static function getVisualElementsArray(target:DisplayObject, collection:Array, ancestors:int = 0):Array {
+ var vo:VisualElementVO;
+
+
+ // do the worm up the display list
+ while (target && ancestors>-1) {
+
+ // store display element information
+ vo = VisualElementVO.unmarshall(target);
+
+ // save reference to display element VO's for tree
+ if (!collection) collection = new Array();
+ collection.push(vo);
+
+ target = target.parent;
+ ancestors--;
+
+ }
+
+ return collection;
+ }
+
+ /**
+ * Get the parent of the target that is also a UIComponent
+ *
+ * @return
+ */
+ public static function getParentUIComponent(target:DisplayObject):UIComponent {
+ var found:Boolean;
+
+ // run up the display list
+ while (target) {
+ target = target.parent;
+
+ // check if next parent exists
+ if (!target) {
+ break;
+ }
+
+ if (target is UIComponent) {
+ found = true;
+ break;
+ }
+
+ }
+
+ if (found) return UIComponent(target);
+ return null;
+ }
+
+ /**
+ * Get the name of the target parent that is also a UIComponent
+ *
+ * @return
+ */
+ public static function getParentUIComponentName(target:DisplayObject):String {
+ var parent:DisplayObject = getParentUIComponent(target);
+ var className:String = getClassName(parent);
+ return className;
+ }
+
+
+ /**
+ * Get parent document name
+ *
+ * @return null if target is not a UIComponent
+ */
+ public static function getParentDocumentName(target:Object):String {
+ var className:String;
+ if (target is UIComponent) {
+ className = getClassName(target.parentDocument);
+ }
+ return className;
+ }
+
+
+ /**
+ * Get parent document name
+ *
+ * @return
+ */
+ public static function getClassNameAndPackage(target:Object):Array {
+ var className:String;
+ var classPath:String;
+
+ className = getClassName(target);
+ classPath = getPackageName(target);
+
+ return [className, classPath];
+ }
+
+
+ /**
+ * Dispatch target change event
+ *
+ * @return
+ */
+ public static function dispatchTargetChangeEvent(target:Object, source:IEventDispatcher):void {
+
+ // let other inspectors know there is a new target selected
+ var selectionChangeEvent:InspectorEvent = new InspectorEvent(InspectorEvent.CHANGE);
+ selectionChangeEvent.targetItem = target;
+
+ // store previous targets in a dictionary
+
+ if (source) {
+ source.dispatchEvent(selectionChangeEvent);
+ }
+ }
+
+
+ /**
+ * Change target. Use this instead of dispatchTargetChangeEvent()
+ *
+ * TODO: Add a weak reference to the old target in a static array for history type navigation
+ *
+ * @return
+ */
+ public static function updateTarget(target:Object, source:IEventDispatcher):void {
+ // TODO: Add a weak reference to the old target in a static array for history type navigation
+
+ // let other inspectors know there is a new target selected
+ var selectionChangeEvent:InspectorEvent = new InspectorEvent(InspectorEvent.CHANGE);
+ selectionChangeEvent.targetItem = target;
+
+ if (source) {
+ source.dispatchEvent(selectionChangeEvent);
+ }
+ }
+
+ /**
+ * Converts an integer to hexidecimal.
+ * For example, 16117809 returns "#EEEEEE" or something
+ * @return
+ */
+ public static function convertIntToHex(item:Object):String {
+ var hex:String = Number(item).toString(16);
+ return ("00000" + hex.toUpperCase()).substr(-6);
+ }
+
+ /**
+ * Get describeType data for the given class.
+ * Can take string, instance or class.
+ * */
+ public static function getDescribeType(object:Object):XML {
+ var describedTypeRecord:mx.utils.DescribeTypeCacheRecord = mx.utils.DescribeTypeCache.describeType(object);
+
+ return describedTypeRecord.typeDescription;
+ }
+
+ /**
+ * Get AccessorMetaData data for the given property.
+ * */
+ public static function getMetaDataOfProperty(target:Object, property:String):AccessorMetaData {
+ var describedTypeRecord:mx.utils.DescribeTypeCacheRecord = mx.utils.DescribeTypeCache.describeType(target);
+ var accessorMetaData:AccessorMetaData = new AccessorMetaData();
+ var matches:XMLList = describedTypeRecord.typeDescription.accessor.(@name==property);
+ var node:XML;
+
+ if (matches.length()>0) {
+ node = matches[0];
+ accessorMetaData.unmarshall(node, target);
+ return accessorMetaData;
+ }
+
+ return null;
+ }
+
+ /**
+ * Get StyleMetaData data for the given style.
+ * */
+ public static function getMetaDataOfStyle(target:Object, style:String, superType:String = null):StyleMetaData {
+ var describedTypeRecord:mx.utils.DescribeTypeCacheRecord;
+ var matches:XMLList;
+ var styleMetaData:StyleMetaData;
+ var extendsClassList:XMLList;
+ var node:XML;
+
+ if (superType) {
+ describedTypeRecord = mx.utils.DescribeTypeCache.describeType(superType);
+ }
+ else {
+ describedTypeRecord = mx.utils.DescribeTypeCache.describeType(target);
+ }
+
+ if (superType || target is String) {
+ matches = describedTypeRecord.typeDescription.factory.metadata.(@name=="Style").arg.(@value==style);
+ }
+ else if (target is Object) {
+ matches = describedTypeRecord.typeDescription.metadata.(@name=="Style").arg.(@value==style);
+ }
+
+ if (matches && matches.length()==0) {
+
+ if (superType || target is String) {
+ extendsClassList = describedTypeRecord.typeDescription.factory.extendsClass;
+ }
+ else if (target is Object) {
+ extendsClassList = describedTypeRecord.typeDescription.extendsClass;
+ }
+
+ var length:int = extendsClassList.length();
+
+ for (var i:int;i<length;i++) {
+ var type:String = extendsClassList[i].@type;
+ if (type=="Class") return null;
+ return getMetaDataOfStyle(target, style, type);
+ }
+
+ }
+
+ if (matches.length()>0) {
+ node = matches[0].parent();
+ styleMetaData = new StyleMetaData();
+ styleMetaData.unmarshall(node, target);
+ return styleMetaData;
+ }
+
+ return null;
+ }
+
+ /**
+ * Creates an array of metadata items for the given object type including inherited metadata.
+ *
+ * For example, if you give it a Spark Button class it gets all the
+ * information for it and then gets it's super class ButtonBase and
+ * adds all that information and so on until it gets to Object. <br/><br/>
+ *
+ * Usage:<br/><pre>
+ * var allStyles:XMLList = concatenateMetaDataXMLItems(myButton, "Style", new XMLList());
+ * </pre>
+ * @param metaType The name of the data in the item name property. Either Style or Event
+ * @param existingItems The list of the data in the item name property
+ * */
+ public static function concatenateMetaDataXMLItems(object:Object, metaType:String, existingItems:XMLList = null):XMLList {
+ var describedTypeRecord:mx.utils.DescribeTypeCacheRecord = mx.utils.DescribeTypeCache.describeType(object);
+ var typeDescription:* = describedTypeRecord.typeDescription;
+ var hasFactory:Boolean = typeDescription.factory.length()>0;
+ var factory:* = typeDescription.factory;
+ var extendsClass:XMLList = typeDescription.extendsClass;
+ var extendsLength:int = extendsClass.length();
+ var list:XMLListCollection = new XMLListCollection(typeDescription.*);
+ // can be on typeDescription.metadata or factory.metadata
+ var isRoot:Boolean = object is String ? false : true;
+ var className:String = !isRoot ? object as String : getQualifiedClassName(object);
+ var itemsLength:int;
+ var itemsList:XMLList;
+ var existingItemsLength:int = existingItems ? existingItems.length() : 0;
+ var metaName:String;
+ var duplicateItems:Array = [];
+
+ if (metaType.toLowerCase()=="style") {
+ metaType = "Style";
+ }
+ else if (metaType.toLowerCase()=="event") {
+ metaType = "Event";
+ }
+
+ if (hasFactory) {
+ //itemsList = factory.metadata.(@name==name); property "name" won't work! no matches found
+ itemsList = factory.metadata.(@name==metaType);
+ }
+ else {
+ itemsList = typeDescription.metadata.(@name==metaType);
+ }
+
+ itemsList = itemsList.copy();
+ itemsLength = itemsList.length();
+
+ //trace("getting info on class : " + className + " for data on " + nAmEe );
+ //trace(" items : " + itemsList);
+
+
+ for (var i:int;i<itemsLength;i++) {
+ var item:XML = XML(itemsList[i]);
+ metaName = item.arg[0].@value;
+ item.@name = metaName;
+ item.@metadataType = metaType;
+ item.@declaredBy = className;
+ //item.@className = className.indexOf("::")!=-1 ? className.split("::")[1] : className;
+ //continue;
+
+ for (var j:int=0;j<existingItemsLength;j++) {
+ var existingItem:XML = existingItems[j];
+
+ if (metaName==existingItem.@name) {
+ delete itemsList[i];
+ itemsLength--;
+ i--;
+ //trace("meta name: " + metaName);
+ //trace("Deleting style: " + existingItem.@name);
+ continue;
+ }
+ }
+ }
+
+
+ if (itemsLength>0) {
+ existingItems = new XMLList(existingItems.toString()+itemsList.toString());
+ }
+
+ if (isRoot && extendsLength>0) {
+ for (i=0;i<extendsLength;i++) {
+ var newClass:String = String(extendsClass[i].@type);
+ existingItems = concatenateMetaDataXMLItems(newClass, metaType, existingItems);
+ }
+ }
+
+ return existingItems;
+ }
+
+
+ /**
+ * Sets the property on the target. Supports styles.
+ * We should probably switch to the set property method
+ * @return
+ */
+ public static function setTargetProperty(target:Object, property:String, value:*, type:String = "String", isPropertyStyle:Object=null):void {
+ var newAssignedValue:* = TypeUtils.getTypedValue(value, type);
+ TypeUtils.applyProperty(target, property, newAssignedValue, type, isPropertyStyle);
+ }
+
+
+ /**
+ * @copy spark.components.gridClasses.GridItemEditor#save();
+ */
+ public static function setProperty(target:Object, field:String, value:*):Boolean {
+
+ var newData:Object = value;
+ var property:String = field;
+ var data:Object = target;
+ var typeInfo:String = "";
+
+ for each(var variable:XML in describeType((data).variable)) {
+ if (property == variable.@name.toString()) {
+ typeInfo = variable.@type.toString();
+ break;
+ }
+ }
+
+ if (typeInfo == "String") {
+ if (!(newData is String))
+ newData = newData.toString();
+ }
+ else if (typeInfo == "uint") {
+ if (!(newData is uint))
+ newData = uint(newData);
+ }
+ else if (typeInfo == "int") {
+ if (!(newData is int))
+ newData = int(newData);
+ }
+ else if (typeInfo == "Number") {
+ if (!(newData is Number))
+ newData = Number(newData);
+ }
+ else if (typeInfo == "Boolean") {
+ if (!(newData is Boolean)) {
+ var strNewData:String = newData.toString();
+
+ if (strNewData) {
+ newData = (strNewData.toLowerCase() == "true") ? true : false;
+ }
+ }
+ }
+
+ if (property && data[property] !== newData) {
+ data[property] = newData;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns <code>true</code> if the object reference specified
+ * is a simple data type. The simple data types include the following:
+ * <ul>
+ * <li><code>String</code></li>
+ * <li><code>Number</code></li>
+ * <li><code>uint</code></li>
+ * <li><code>int</code></li>
+ * <li><code>Boolean</code></li>
+ * <li><code>Date</code></li>
+ * <li><code>Array</code></li>
+ * </ul>
+ *
+ * @param value Object inspected.
+ *
+ * @return <code>true</code> if the object specified
+ * is one of the types above; <code>false</code> otherwise.
+ * */
+ public static function isSimple(value:*):Boolean {
+ return ObjectUtil.isSimple(value);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-radii8/blob/f370bfcf/Radii8Library/src/com/flexcapacitor/utils/DocumentExporter.as
----------------------------------------------------------------------
diff --git a/Radii8Library/src/com/flexcapacitor/utils/DocumentExporter.as b/Radii8Library/src/com/flexcapacitor/utils/DocumentExporter.as
new file mode 100644
index 0000000..381a2ce
--- /dev/null
+++ b/Radii8Library/src/com/flexcapacitor/utils/DocumentExporter.as
@@ -0,0 +1,199 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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 com.flexcapacitor.utils {
+ import com.flexcapacitor.events.HistoryEvent;
+ import com.flexcapacitor.events.HistoryEventItem;
+ import com.flexcapacitor.model.IDocument;
+ import com.flexcapacitor.utils.supportClasses.ComponentDescription;
+
+ import mx.collections.ArrayCollection;
+
+ /**
+ * Exports document
+ * */
+ public class DocumentExporter {
+
+ /**
+ * Constructor
+ * */
+ public function DocumentExporter() {
+
+ }
+
+ private var _isValid:Boolean;
+
+ /**
+ * Indicates if the XML validation
+ * */
+ [Bindable]
+ public function get isValid():Boolean {
+ return _isValid;
+ }
+
+ /**
+ * @private
+ */
+ public function set isValid(value:Boolean):void {
+ _isValid = value;
+ }
+
+
+ private var _error:Error;
+
+ /**
+ * Validation error
+ * */
+ [Bindable]
+ public function get error():Error {
+ return _error;
+ }
+
+ /**
+ * @private
+ */
+ public function set error(value:Error):void {
+ _error = value;
+ }
+
+
+ private var _errorMessage:String;
+
+ /**
+ * Validation error message
+ * */
+ [Bindable]
+ public function get errorMessage():String {
+ return _errorMessage;
+ }
+
+ /**
+ * @private
+ */
+ public function set errorMessage(value:String):void {
+ _errorMessage = value;
+ }
+
+
+ private var _errors:Array = [];
+
+ /**
+ * Error messages
+ * */
+ [Bindable]
+ public function get errors():Array {
+ return _errors;
+ }
+
+ /**
+ * @private
+ */
+ public function set errors(value:Array):void {
+ _errors = value;
+ }
+
+ private var _warnings:Array = [];
+
+ /**
+ * Warning messages
+ * */
+ [Bindable]
+ public function get warnings():Array {
+ return _warnings;
+ }
+
+ /**
+ * @private
+ */
+ public function set warnings(value:Array):void {
+ _warnings = value;
+ }
+
+
+ public var target:Object;
+
+
+ /**
+ * Get an object that contains the properties that have been set on the component.
+ * This does this by going through the history events and checking the changes.
+ *
+ * WE SHOULD CHANGE THIS
+ * */
+ public function getAppliedPropertiesFromHistory(document:IDocument, component:ComponentDescription, addToProperties:Boolean = true):Object {
+ var historyIndex:int = document.historyIndex;
+ var historyEvent:HistoryEventItem;
+ var historyItem:HistoryEvent;
+ var history:ArrayCollection;
+ var historyEvents:Array;
+ var eventsLength:int;
+ var propertiesObject:Object;
+ var stylesObject:Object;
+ var properties:Array;
+ var styles:Array;
+
+ history = document.history;
+ propertiesObject = {};
+ stylesObject = {};
+
+ if (history.length==0) return propertiesObject;
+
+ // go back through the history of changes and
+ // add the properties that have been set to an object
+ for (var i:int=historyIndex+1;i--;) {
+ historyItem = history.getItemAt(i) as HistoryEvent;
+ historyEvents = historyItem.historyEventItems;
+ eventsLength = historyEvents.length;
+
+ for (var j:int=0;j<eventsLength;j++) {
+ historyEvent = historyEvents[j] as HistoryEventItem;
+ properties = historyEvent.properties;
+ styles = historyEvent.styles;
+
+ if (historyEvent.targets.indexOf(component.instance)!=-1) {
+ for each (var property:String in properties) {
+
+ if (property in propertiesObject) {
+ continue;
+ }
+ else {
+ propertiesObject[property] = historyEvent.propertyChanges.end[property];
+ }
+ }
+
+ for each (var style:String in styles) {
+
+ if (style in stylesObject) {
+ continue;
+ }
+ else {
+ stylesObject[style] = historyEvent.propertyChanges.end[style];
+ }
+ }
+ }
+
+ }
+ }
+
+ component.properties = propertiesObject;
+ component.styles = stylesObject;
+
+ return propertiesObject;
+ }
+ }
+}
\ No newline at end of file