using System; using System.IO; using System.Collections; using System.Drawing; using System.ComponentModel; using System.Reflection; using System.Collections.Generic; using System.Text; using System.Globalization; namespace FastReport.Utils { /// /// Specifies the target for the serialize operation. /// public enum SerializeTo { /// /// Serialize to the report file. /// Report, /// /// Serialize to the preview pages. /// Preview, /// /// Serialize to the source pages of a preview. /// SourcePages, /// /// Serialize to the designer's clipboard. /// Clipboard, /// /// Serialize to the designer's undo/redo buffer. /// Undo } internal class DiffEventArgs { private object obj; private object diffObject; public object Object { get { return obj; } set { obj = value; } } public object DiffObject { get { return diffObject; } set { diffObject = value; } } } internal delegate void DiffEventHandler(object sender, DiffEventArgs e); /// /// The writer used to serialize object's properties to a report file. /// public class FRWriter : IDisposable { #region Fields private XmlDocument doc; private XmlItem root; private XmlItem curItem; private XmlItem curRoot; //private StringBuilder FText; private object diffObject; private bool saveChildren; private bool writeHeader; private BlobStore blobStore; private SerializeTo serializeTo; private Hashtable diffObjects; #endregion #region Properties internal event DiffEventHandler GetDiff; internal BlobStore BlobStore { get { return blobStore; } set { blobStore = value; } } /// /// Gets or sets current xml item name. /// public string ItemName { get { return curItem.Name; } set { curItem.Name = value; } } /// /// Gets or sets target of serialization. /// public SerializeTo SerializeTo { get { return serializeTo; } set { serializeTo = value; } } /// /// Gets the ethalon object to compare with. /// public object DiffObject { get { return diffObject; } } /// /// Gets or sets a value that determines whether is necessary to serialize child objects. /// public bool SaveChildren { get { return saveChildren; } set { saveChildren = value; } } /// /// Gets or sets a value that determines whether is necessary to add xml header. /// public bool WriteHeader { get { return writeHeader; } set { writeHeader = value; } } #endregion #region Private Methods private string PropName(string name) { return serializeTo == SerializeTo.Preview ? ShortProperties.GetShortName(name) : name; } #endregion #region Public Methods /// /// Serializes the specified object. /// /// The object to serialize. /// /// The object must implement the interface. This method /// invokes the Serialize method of the object. /// /// This example demonstrates the use of writer. /// /// public void Serialize(FRWriter writer) /// { /// // get the etalon object. It will be used to write changed properties only. /// Base c = writer.DiffObject as Base; /// /// // write the type name /// writer.ItemName = ClassName; /// /// // write properties /// if (Name != "") /// writer.WriteStr("Name", Name); /// if (Restrictions != c.Restrictions) /// writer.WriteValue("Restrictions", Restrictions); /// /// // write child objects if allowed /// if (writer.SaveChildren) /// { /// foreach (Base child in ChildObjects) /// { /// writer.Write(child); /// } /// } /// } /// /// public void Write(IFRSerializable obj) { Write(obj, null); } /// /// Serializes the object using specified etalon. /// /// The object to serialize. /// The etalon object. public void Write(IFRSerializable obj, object diff) { if (obj == null) return; XmlItem saveCurItem = curItem; XmlItem saveCurRoot = curRoot; //StringBuilder saveText = FText; object saveDiffObject = diffObject; try { //FText = new StringBuilder(); curItem = curItem == null ? root : curItem.Add(); curRoot = curItem; diffObject = diff; if (obj is Base && SerializeTo == SerializeTo.Preview) { diffObject = (obj as Base).OriginalComponent; curItem.Name = diffObject != null ? (obj as Base).Alias : (obj as Base).ClassName; } if (GetDiff != null) { DiffEventArgs e = new DiffEventArgs(); e.Object = obj; GetDiff(this, e); diffObject = e.DiffObject; } if (diffObject == null) { try { Type objType = obj.GetType(); if (!diffObjects.Contains(objType)) diffObjects[objType] = Activator.CreateInstance(objType); diffObject = diffObjects[objType]; } catch { } } obj.Serialize(this); } finally { //if (FText.Length > 0) // FText.Remove(FText.Length - 1, 1); //FCurRoot.Text = FText.ToString(); //FText = saveText; curItem = saveCurItem; curRoot = saveCurRoot; diffObject = saveDiffObject; } } /// /// Writes a string property. /// /// Property name. /// Property value. public void WriteStr(string name, string value) { curRoot.SetProp(PropName(name), value); //FText.Append(PropName(name)); //FText.Append("=\""); //FText.Append(Converter.ToXml(value)); //FText.Append("\" "); } /// /// Writes a boolean property. /// /// Property name. /// Property value. public void WriteBool(string name, bool value) { curRoot.SetProp(PropName(name), value ? "true" : "false"); // FText.Append(PropName(name)); //FText.Append("=\""); //FText.Append(value ? "true" : "false"); //FText.Append("\" "); } /// /// Writes an integer property. /// /// Property name. /// Property value. public void WriteInt(string name, int value) { curRoot.SetProp(PropName(name), value.ToString()); //FText.Append(PropName(name)); //FText.Append("=\""); //FText.Append(value.ToString()); //FText.Append("\" "); } /// /// Writes a float property. /// /// Property name. /// Property value. public void WriteFloat(string name, float value) { curRoot.SetProp(PropName(name), value.ToString(CultureInfo.InvariantCulture.NumberFormat)); //FText.Append(PropName(name)); //FText.Append("=\""); //FText.Append(value.ToString(CultureInfo.InvariantCulture.NumberFormat)); //FText.Append("\" "); } /// /// Writes a double property. /// /// Property name. /// Property value. public void WriteDouble(string name, double value) { curRoot.SetProp(PropName(name), value.ToString(CultureInfo.InvariantCulture.NumberFormat)); //FText.Append(PropName(name)); //FText.Append("=\""); //FText.Append(value.ToString(CultureInfo.InvariantCulture.NumberFormat)); //FText.Append("\" "); } /// /// Writes an enumeration property. /// /// Property name. /// Property value. public void WriteValue(string name, object value) { curRoot.SetProp(PropName(name), value != null ? Converter.ToString(value) : "null"); //FText.Append(PropName(name)); //FText.Append("=\""); //FText.Append(value != null ? Converter.ToXml(value) : "null"); //FText.Append("\" "); } /// /// Writes an object reference property. /// /// Property name. /// Property value. public void WriteRef(string name, Base value) { curRoot.SetProp(PropName(name), value != null ? value.Name : "null"); //FText.Append(PropName(name)); //FText.Append("=\""); //FText.Append(value != null ? value.Name : "null"); //FText.Append("\" "); } /// /// Writes a standalone property value. /// /// Name of property. /// Property value. /// /// This method produces the following output: /// <PropertyName>PropertyValue</PropertyName> /// public void WritePropertyValue(string name, string value) { XmlItem item = curItem.Add(); item.Name = name; item.Value = value; } /// /// Determines if two objects are equal. /// /// The first object. /// The second object. /// true if objects will be serialized to the same value. public bool AreEqual(object obj1, object obj2) { if (obj1 == obj2) return true; if (obj1 == null || obj2 == null) return false; string s1 = Converter.ToString(obj1); string s2 = Converter.ToString(obj2); return s1 == s2; } /// /// Disposes the writer. /// public void Dispose() { doc.Dispose(); foreach (object obj in diffObjects.Values) { if (obj is IDisposable) (obj as IDisposable).Dispose(); } } /// /// Saves the writer output to a stream. /// /// Stream to save to. public void Save(Stream stream) { doc.AutoIndent = serializeTo == SerializeTo.Report; doc.WriteHeader = WriteHeader; doc.Save(stream); } #endregion /// /// Initializes a new instance of the FRWriter class with default settings. /// public FRWriter() { doc = new XmlDocument(); root = doc.Root; //FText = new StringBuilder(); saveChildren = true; writeHeader = true; diffObjects = new Hashtable(); } /// /// Initializes a new instance of the FRWriter class with specified xml item that will /// receive writer's output. /// /// The xml item that will receive writer's output. public FRWriter(XmlItem root) : this() { this.root = root; } } }