//
//
//
//
// $Revision: 5740 $
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ICSharpCode.Core
{
///
/// This interface flags an object beeing "mementocapable". This means that the
/// state of the object could be saved to an object
/// and set from a object from the same class.
/// This is used to save and restore the state of GUI objects.
///
public interface IMementoCapable
{
///
/// Creates a new memento from the state.
///
Properties CreateMemento();
///
/// Sets the state to the given memento.
///
void SetMemento(Properties memento);
}
///
/// Description of PropertyGroup.
///
public class Properties
{
/// Needed for support of late deserialization
class SerializedValue {
string content;
public string Content {
get { return content; }
}
public T Deserialize()
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(new StringReader(content));
}
public SerializedValue(string content)
{
this.content = content;
}
}
Dictionary properties = new Dictionary();
public string this[string property] {
get {
return Convert.ToString(Get(property), CultureInfo.InvariantCulture);
}
set {
Set(property, value);
}
}
public string[] Elements
{
get {
lock (properties) {
List ret = new List();
foreach (KeyValuePair property in properties)
ret.Add(property.Key);
return ret.ToArray();
}
}
}
public object Get(string property)
{
lock (properties) {
object val;
properties.TryGetValue(property, out val);
return val;
}
}
public void Set(string property, T value)
{
if (property == null)
throw new ArgumentNullException("property");
if (value == null)
throw new ArgumentNullException("value");
T oldValue = default(T);
lock (properties) {
if (!properties.ContainsKey(property)) {
properties.Add(property, value);
} else {
oldValue = Get(property, value);
properties[property] = value;
}
}
OnPropertyChanged(new PropertyChangedEventArgs(this, property, oldValue, value));
}
public bool Contains(string property)
{
lock (properties) {
return properties.ContainsKey(property);
}
}
public int Count {
get {
lock (properties) {
return properties.Count;
}
}
}
public bool Remove(string property)
{
lock (properties) {
return properties.Remove(property);
}
}
public override string ToString()
{
lock (properties) {
StringBuilder sb = new StringBuilder();
sb.Append("[Properties:{");
foreach (KeyValuePair entry in properties) {
sb.Append(entry.Key);
sb.Append("=");
sb.Append(entry.Value);
sb.Append(",");
}
sb.Append("}]");
return sb.ToString();
}
}
public static Properties ReadFromAttributes(XmlReader reader)
{
Properties properties = new Properties();
if (reader.HasAttributes) {
for (int i = 0; i < reader.AttributeCount; i++) {
reader.MoveToAttribute(i);
properties[reader.Name] = reader.Value;
}
reader.MoveToElement(); //Moves the reader back to the element node.
}
return properties;
}
internal void ReadProperties(XmlReader reader, string endElement)
{
if (reader.IsEmptyElement) {
return;
}
while (reader.Read()) {
switch (reader.NodeType) {
case XmlNodeType.EndElement:
if (reader.LocalName == endElement) {
return;
}
break;
case XmlNodeType.Element:
string propertyName = reader.LocalName;
if (propertyName == "Properties") {
propertyName = reader.GetAttribute(0);
Properties p = new Properties();
p.ReadProperties(reader, "Properties");
properties[propertyName] = p;
} else if (propertyName == "Array") {
propertyName = reader.GetAttribute(0);
properties[propertyName] = ReadArray(reader);
} else if (propertyName == "SerializedValue") {
propertyName = reader.GetAttribute(0);
properties[propertyName] = new SerializedValue(reader.ReadInnerXml());
} else {
properties[propertyName] = reader.HasAttributes ? reader.GetAttribute(0) : null;
}
break;
}
}
}
ArrayList ReadArray(XmlReader reader)
{
if (reader.IsEmptyElement)
return new ArrayList(0);
ArrayList l = new ArrayList();
while (reader.Read()) {
switch (reader.NodeType) {
case XmlNodeType.EndElement:
if (reader.LocalName == "Array") {
return l;
}
break;
case XmlNodeType.Element:
l.Add(reader.HasAttributes ? reader.GetAttribute(0) : null);
break;
}
}
return l;
}
public void WriteProperties(XmlWriter writer)
{
lock (properties) {
List> sortedProperties = new List>(properties);
sortedProperties.Sort((a, b) => StringComparer.OrdinalIgnoreCase.Compare(a.Key, b.Key));
foreach (KeyValuePair entry in sortedProperties) {
object val = entry.Value;
if (val is Properties) {
writer.WriteStartElement("Properties");
writer.WriteAttributeString("name", entry.Key);
((Properties)val).WriteProperties(writer);
writer.WriteEndElement();
} else if (val is Array || val is ArrayList) {
writer.WriteStartElement("Array");
writer.WriteAttributeString("name", entry.Key);
foreach (object o in (IEnumerable)val) {
writer.WriteStartElement("Element");
WriteValue(writer, o);
writer.WriteEndElement();
}
writer.WriteEndElement();
} else if (TypeDescriptor.GetConverter(val).CanConvertFrom(typeof(string))) {
writer.WriteStartElement(entry.Key);
WriteValue(writer, val);
writer.WriteEndElement();
} else if (val is SerializedValue) {
writer.WriteStartElement("SerializedValue");
writer.WriteAttributeString("name", entry.Key);
writer.WriteRaw(((SerializedValue)val).Content);
writer.WriteEndElement();
} else {
writer.WriteStartElement("SerializedValue");
writer.WriteAttributeString("name", entry.Key);
XmlSerializer serializer = new XmlSerializer(val.GetType());
serializer.Serialize(writer, val, null);
writer.WriteEndElement();
}
}
}
}
void WriteValue(XmlWriter writer, object val)
{
if (val != null) {
if (val is string) {
writer.WriteAttributeString("value", val.ToString());
} else {
TypeConverter c = TypeDescriptor.GetConverter(val.GetType());
writer.WriteAttributeString("value", c.ConvertToInvariantString(val));
}
}
}
public void Save(string fileName)
{
using (XmlTextWriter writer = new XmlTextWriter(fileName, Encoding.UTF8)) {
writer.Formatting = Formatting.Indented;
writer.WriteStartElement("Properties");
WriteProperties(writer);
writer.WriteEndElement();
}
}
// public void BinarySerialize(BinaryWriter writer)
// {
// writer.Write((byte)properties.Count);
// foreach (KeyValuePair entry in properties) {
// writer.Write(AddInTree.GetNameOffset(entry.Key));
// writer.Write(AddInTree.GetNameOffset(entry.Value.ToString()));
// }
// }
public static Properties Load(string fileName)
{
if (!File.Exists(fileName)) {
return null;
}
using (XmlTextReader reader = new XmlTextReader(fileName)) {
while (reader.Read()){
if (reader.IsStartElement()) {
switch (reader.LocalName) {
case "Properties":
Properties properties = new Properties();
properties.ReadProperties(reader, "Properties");
return properties;
}
}
}
}
return null;
}
public T Get(string property, T defaultValue)
{
lock (properties) {
object o;
if (!properties.TryGetValue(property, out o)) {
properties.Add(property, defaultValue);
return defaultValue;
}
if (o is string && typeof(T) != typeof(string)) {
TypeConverter c = TypeDescriptor.GetConverter(typeof(T));
try {
o = c.ConvertFromInvariantString(o.ToString());
} catch (Exception ex) {
MessageService.ShowWarning("Error loading property '" + property + "': " + ex.Message);
o = defaultValue;
}
properties[property] = o; // store for future look up
} else if (o is ArrayList && typeof(T).IsArray) {
ArrayList list = (ArrayList)o;
Type elementType = typeof(T).GetElementType();
Array arr = System.Array.CreateInstance(elementType, list.Count);
TypeConverter c = TypeDescriptor.GetConverter(elementType);
try {
for (int i = 0; i < arr.Length; ++i) {
if (list[i] != null) {
arr.SetValue(c.ConvertFromInvariantString(list[i].ToString()), i);
}
}
o = arr;
} catch (Exception ex) {
MessageService.ShowWarning("Error loading property '" + property + "': " + ex.Message);
o = defaultValue;
}
properties[property] = o; // store for future look up
} else if (!(o is string) && typeof(T) == typeof(string)) {
TypeConverter c = TypeDescriptor.GetConverter(typeof(T));
if (c.CanConvertTo(typeof(string))) {
o = c.ConvertToInvariantString(o);
} else {
o = o.ToString();
}
} else if (o is SerializedValue) {
try {
o = ((SerializedValue)o).Deserialize();
} catch (Exception ex) {
MessageService.ShowWarning("Error loading property '" + property + "': " + ex.Message);
o = defaultValue;
}
properties[property] = o; // store for future look up
}
try {
return (T)o;
} catch (NullReferenceException) {
// can happen when configuration is invalid -> o is null and a value type is expected
return defaultValue;
}
}
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null) {
PropertyChanged(this, e);
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}