context: /********************************************************************
   *
   *  PropertyBag.cs
   *  --------------
   *  Copyright (C) 2002  Tony Allowatt
   *  Last Update: 12/14/2002
   * 
   *  THE SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS", WITHOUT WARRANTY
   *  OF ANY KIND, EXPRESS OR IMPLIED. IN NO EVENT SHALL THE AUTHOR BE
   *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING FROM,
   *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF THIS
   *  SOFTWARE.
   * 
   *  Public types defined in this file:
   *  ----------------------------------
   *  namespace Flobbster.Windows.Forms
   *     class PropertySpec
   *     class PropertySpecEventArgs
   *     delegate PropertySpecEventHandler
   *     class PropertyBag
   *        class PropertyBag.PropertySpecCollection
   *     class PropertyTable
   *
   ********************************************************************/
  
  using System;
  using System.Collections;
  using System.ComponentModel;
  using System.Drawing.Design;
  
  namespace MathExp
  {
  	/// <summary>
  	/// Represents a single property in a PropertySpec.
  	/// </summary>
  	public class PropertySpec
  	{
  		private Attribute[] attributes;
  		private string category;
  		private object defaultValue;
  		private string description;
  		private string editor;
  		private string name;
  		private string type;
  		private string typeConverter;
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">The fully qualified name of the type of the property.</param>
  		public PropertySpec(string name, string type) : this(name, type, null, null, null) { }
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">A Type that represents the type of the property.</param>
  		public PropertySpec(string name, Type type) :
  			this(name, type.AssemblyQualifiedName, null, null, null) { }
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">The fully qualified name of the type of the property.</param>
  		/// <param name="category">The category under which the property is displayed in the
  		/// property grid.</param>
  		public PropertySpec(string name, string type, string category) : this(name, type, category, null, null) { }
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">A Type that represents the type of the property.</param>
  		/// <param name="category"></param>
  		public PropertySpec(string name, Type type, string category) :
  			this(name, type.AssemblyQualifiedName, category, null, null) { }
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">The fully qualified name of the type of the property.</param>
  		/// <param name="category">The category under which the property is displayed in the
  		/// property grid.</param>
  		/// <param name="description">A string that is displayed in the help area of the
  		/// property grid.</param>
  		public PropertySpec(string name, string type, string category, string description) :
  			this(name, type, category, description, null) { }
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">A Type that represents the type of the property.</param>
  		/// <param name="category">The category under which the property is displayed in the
  		/// property grid.</param>
  		/// <param name="description">A string that is displayed in the help area of the
  		/// property grid.</param>
  		public PropertySpec(string name, Type type, string category, string description) :
  			this(name, type.AssemblyQualifiedName, category, description, null) { }
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">The fully qualified name of the type of the property.</param>
  		/// <param name="category">The category under which the property is displayed in the
  		/// property grid.</param>
  		/// <param name="description">A string that is displayed in the help area of the
  		/// property grid.</param>
  		/// <param name="defaultValue">The default value of the property, or null if there is
  		/// no default value.</param>
  		public PropertySpec(string name, string type, string category, string description, object defaultValue)
  		{
  			this.name = name;
  			this.type = type;
  			this.category = category;
  			this.description = description;
  			this.defaultValue = defaultValue;
  			this.attributes = null;
  		}
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">A Type that represents the type of the property.</param>
  		/// <param name="category">The category under which the property is displayed in the
  		/// property grid.</param>
  		/// <param name="description">A string that is displayed in the help area of the
  		/// property grid.</param>
  		/// <param name="defaultValue">The default value of the property, or null if there is
  		/// no default value.</param>
  		public PropertySpec(string name, Type type, string category, string description, object defaultValue) :
  			this(name, type.AssemblyQualifiedName, category, description, defaultValue) { }
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">The fully qualified name of the type of the property.</param>
  		/// <param name="category">The category under which the property is displayed in the
  		/// property grid.</param>
  		/// <param name="description">A string that is displayed in the help area of the
  		/// property grid.</param>
  		/// <param name="defaultValue">The default value of the property, or null if there is
  		/// no default value.</param>
  		/// <param name="editor">The fully qualified name of the type of the editor for this
  		/// property.  This type must derive from UITypeEditor.</param>
  		/// <param name="typeConverter">The fully qualified name of the type of the type
  		/// converter for this property.  This type must derive from TypeConverter.</param>
  		public PropertySpec(string name, string type, string category, string description, object defaultValue,
  			string editor, string typeConverter) : this(name, type, category, description, defaultValue)
  		{
  			this.editor = editor;
  			this.typeConverter = typeConverter;
  		}
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">A Type that represents the type of the property.</param>
  		/// <param name="category">The category under which the property is displayed in the
  		/// property grid.</param>
  		/// <param name="description">A string that is displayed in the help area of the
  		/// property grid.</param>
  		/// <param name="defaultValue">The default value of the property, or null if there is
  		/// no default value.</param>
  		/// <param name="editor">The fully qualified name of the type of the editor for this
  		/// property.  This type must derive from UITypeEditor.</param>
  		/// <param name="typeConverter">The fully qualified name of the type of the type
  		/// converter for this property.  This type must derive from TypeConverter.</param>
  		public PropertySpec(string name, Type type, string category, string description, object defaultValue,
  			string editor, string typeConverter) :
  			this(name, type.AssemblyQualifiedName, category, description, defaultValue, editor, typeConverter) { }
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">The fully qualified name of the type of the property.</param>
  		/// <param name="category">The category under which the property is displayed in the
  		/// property grid.</param>
  		/// <param name="description">A string that is displayed in the help area of the
  		/// property grid.</param>
  		/// <param name="defaultValue">The default value of the property, or null if there is
  		/// no default value.</param>
  		/// <param name="editor">The Type that represents the type of the editor for this
  		/// property.  This type must derive from UITypeEditor.</param>
  		/// <param name="typeConverter">The fully qualified name of the type of the type
  		/// converter for this property.  This type must derive from TypeConverter.</param>
  		public PropertySpec(string name, string type, string category, string description, object defaultValue,
  			Type editor, string typeConverter) :
  			this(name, type, category, description, defaultValue, editor.AssemblyQualifiedName,
  			typeConverter) { }
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">A Type that represents the type of the property.</param>
  		/// <param name="category">The category under which the property is displayed in the
  		/// property grid.</param>
  		/// <param name="description">A string that is displayed in the help area of the
  		/// property grid.</param>
  		/// <param name="defaultValue">The default value of the property, or null if there is
  		/// no default value.</param>
  		/// <param name="editor">The Type that represents the type of the editor for this
  		/// property.  This type must derive from UITypeEditor.</param>
  		/// <param name="typeConverter">The fully qualified name of the type of the type
  		/// converter for this property.  This type must derive from TypeConverter.</param>
  		public PropertySpec(string name, Type type, string category, string description, object defaultValue,
  			Type editor, string typeConverter) : 
  			this(name, type.AssemblyQualifiedName, category, description, defaultValue,
  			editor.AssemblyQualifiedName, typeConverter) { }
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">The fully qualified name of the type of the property.</param>
  		/// <param name="category">The category under which the property is displayed in the
  		/// property grid.</param>
  		/// <param name="description">A string that is displayed in the help area of the
  		/// property grid.</param>
  		/// <param name="defaultValue">The default value of the property, or null if there is
  		/// no default value.</param>
  		/// <param name="editor">The fully qualified name of the type of the editor for this
  		/// property.  This type must derive from UITypeEditor.</param>
  		/// <param name="typeConverter">The Type that represents the type of the type
  		/// converter for this property.  This type must derive from TypeConverter.</param>
  		public PropertySpec(string name, string type, string category, string description, object defaultValue,
  			string editor, Type typeConverter) :
  			this(name, type, category, description, defaultValue, editor, typeConverter.AssemblyQualifiedName) { }
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">A Type that represents the type of the property.</param>
  		/// <param name="category">The category under which the property is displayed in the
  		/// property grid.</param>
  		/// <param name="description">A string that is displayed in the help area of the
  		/// property grid.</param>
  		/// <param name="defaultValue">The default value of the property, or null if there is
  		/// no default value.</param>
  		/// <param name="editor">The fully qualified name of the type of the editor for this
  		/// property.  This type must derive from UITypeEditor.</param>
  		/// <param name="typeConverter">The Type that represents the type of the type
  		/// converter for this property.  This type must derive from TypeConverter.</param>
  		public PropertySpec(string name, Type type, string category, string description, object defaultValue,
  			string editor, Type typeConverter) :
  			this(name, type.AssemblyQualifiedName, category, description, defaultValue, editor,
  			typeConverter.AssemblyQualifiedName) { }
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">The fully qualified name of the type of the property.</param>
  		/// <param name="category">The category under which the property is displayed in the
  		/// property grid.</param>
  		/// <param name="description">A string that is displayed in the help area of the
  		/// property grid.</param>
  		/// <param name="defaultValue">The default value of the property, or null if there is
  		/// no default value.</param>
  		/// <param name="editor">The Type that represents the type of the editor for this
  		/// property.  This type must derive from UITypeEditor.</param>
  		/// <param name="typeConverter">The Type that represents the type of the type
  		/// converter for this property.  This type must derive from TypeConverter.</param>
  		public PropertySpec(string name, string type, string category, string description, object defaultValue,
  			Type editor, Type typeConverter) :
  			this(name, type, category, description, defaultValue, editor.AssemblyQualifiedName,
  			typeConverter.AssemblyQualifiedName) { }
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpec class.
  		/// </summary>
  		/// <param name="name">The name of the property displayed in the property grid.</param>
  		/// <param name="type">A Type that represents the type of the property.</param>
  		/// <param name="category">The category under which the property is displayed in the
  		/// property grid.</param>
  		/// <param name="description">A string that is displayed in the help area of the
  		/// property grid.</param>
  		/// <param name="defaultValue">The default value of the property, or null if there is
  		/// no default value.</param>
  		/// <param name="editor">The Type that represents the type of the editor for this
  		/// property.  This type must derive from UITypeEditor.</param>
  		/// <param name="typeConverter">The Type that represents the type of the type
  		/// converter for this property.  This type must derive from TypeConverter.</param>
  		public PropertySpec(string name, Type type, string category, string description, object defaultValue,
  			Type editor, Type typeConverter) :
  			this(name, type.AssemblyQualifiedName, category, description, defaultValue,
  			editor.AssemblyQualifiedName, typeConverter.AssemblyQualifiedName) { }
  
  		/// <summary>
  		/// Gets or sets a collection of additional Attributes for this property.  This can
  		/// be used to specify attributes beyond those supported intrinsically by the
  		/// PropertySpec class, such as ReadOnly and Browsable.
  		/// </summary>
  		public Attribute[] Attributes
  		{
  			get { return attributes; }
  			set { attributes = value; }
  		}
  
  		/// <summary>
  		/// Gets or sets the category name of this property.
  		/// </summary>
  		public string Category
  		{
  			get { return category; }
  			set { category = value; }
  		}
  
  		/// <summary>
  		/// Gets or sets the fully qualified name of the type converter
  		/// type for this property.
  		/// </summary>
  		public string ConverterTypeName
  		{
  			get { return typeConverter; }
  			set { typeConverter = value; }
  		}
  
  		/// <summary>
  		/// Gets or sets the default value of this property.
  		/// </summary>
  		public object DefaultValue
  		{
  			get { return defaultValue; }
  			set { defaultValue = value; }
  		}
  
  		/// <summary>
  		/// Gets or sets the help text description of this property.
  		/// </summary>
  		public string Description
  		{
  			get { return description; }
  			set { description = value; }
  		}
  
  		/// <summary>
  		/// Gets or sets the fully qualified name of the editor type for
  		/// this property.
  		/// </summary>
  		public string EditorTypeName
  		{
  			get { return editor; }
  			set { editor = value; }
  		}
  
  		/// <summary>
  		/// Gets or sets the name of this property.
  		/// </summary>
  		public string Name
  		{
  			get { return name; }
  			set { name = value; }
  		}
  
  		/// <summary>
  		/// Gets or sets the fully qualfied name of the type of this
  		/// property.
  		/// </summary>
  		public string TypeName
  		{
  			get { return type; }
  			set { type = value; }
  		}
  	}
  
  	/// <summary>
  	/// Provides data for the GetValue and SetValue events of the PropertyBag class.
  	/// </summary>
  	public class PropertySpecEventArgs : EventArgs
  	{
  		private PropertySpec property;
  		private object val;
  
  		/// <summary>
  		/// Initializes a new instance of the PropertySpecEventArgs class.
  		/// </summary>
  		/// <param name="property">The PropertySpec that represents the property whose
  		/// value is being requested or set.</param>
  		/// <param name="val">The current value of the property.</param>
  		public PropertySpecEventArgs(PropertySpec property, object val)
  		{
  			this.property = property;
  			this.val = val;
  		}
  
  		/// <summary>
  		/// Gets the PropertySpec that represents the property whose value is being
  		/// requested or set.
  		/// </summary>
  		public PropertySpec Property
  		{
  			get { return property; }
  		}
  
  		/// <summary>
  		/// Gets or sets the current value of the property.
  		/// </summary>
  		public object Value
  		{
  			get { return val; }
  			set { val = value; }
  		}
  	}
  
  	/// <summary>
  	/// Represents the method that will handle the GetValue and SetValue events of the
  	/// PropertyBag class.
  	/// </summary>
  	public delegate void PropertySpecEventHandler(object sender, PropertySpecEventArgs e);
  
  	/// <summary>
  	/// Represents a collection of custom properties that can be selected into a
  	/// PropertyGrid to provide functionality beyond that of the simple reflection
  	/// normally used to query an object's properties.
  	/// </summary>
  	public class PropertyBag : ICustomTypeDescriptor
  	{
  		#region PropertySpecCollection class definition
  		/// <summary>
  		/// Encapsulates a collection of PropertySpec objects.
  		/// </summary>
  		[Serializable]
  		public class PropertySpecCollection : IList
  		{
  			private ArrayList innerArray;
  			
  			/// <summary>
  			/// Initializes a new instance of the PropertySpecCollection class.
  			/// </summary>
  			public PropertySpecCollection()
  			{
  				innerArray = new ArrayList();
  			}
  
  			/// <summary>
  			/// Gets the number of elements in the PropertySpecCollection.
  			/// </summary>
  			/// <value>
  			/// The number of elements contained in the PropertySpecCollection.
  			/// </value>
  			public int Count
  			{
  				get { return innerArray.Count; }
  			}
  
  			/// <summary>
  			/// Gets a value indicating whether the PropertySpecCollection has a fixed size.
  			/// </summary>
  			/// <value>
  			/// true if the PropertySpecCollection has a fixed size; otherwise, false.
  			/// </value>
  			public bool IsFixedSize
  			{
  				get { return false; }
  			}
  			
  			/// <summary>
  			/// Gets a value indicating whether the PropertySpecCollection is read-only.
  			/// </summary>
  			public bool IsReadOnly
  			{
  				get { return false; }
  			}
  
  			/// <summary>
  			/// Gets a value indicating whether access to the collection is synchronized (thread-safe).
  			/// </summary>
  			/// <value>
  			/// true if access to the PropertySpecCollection is synchronized (thread-safe); otherwise, false.
  			/// </value>
  			public bool IsSynchronized
  			{
  
gt: 				get { return false; }