2007-08-28 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / BindingContext.cs
index b0205d80c6d52e93cc42118ecdc91e244a2655f1..2d260d1e60d686e10d6cc2bd3fb6cd3adb42533b 100644 (file)
@@ -24,6 +24,7 @@
 //     Jackson Harper  jackson@ximian.com
 
 
+using System.Data;
 using System.Collections;
 using System.Globalization;
 using System.ComponentModel;
@@ -35,41 +36,29 @@ namespace System.Windows.Forms {
        public class BindingContext : ICollection, IEnumerable {
 
                private Hashtable managers;
+               private EventHandler onCollectionChangedHandler;
 
-               private class ManagerEntry {
+               private class HashKey {
+                       public object source;
+                       public string member;
 
-                       private object source;
-                       private WeakReference member_ref;
-                       
-                       private int member_hash;
-
-                       public ManagerEntry (object source, string member)
+                       public HashKey (object source, string member)
                        {
                                this.source = source;
-                               if (member == null)
-                                       member = String.Empty;
-                               
-                               member_hash = member.ToLower (CultureInfo.InvariantCulture).GetHashCode ();
-                               if (member_hash == 0)
-                                       member_hash = 1;
-                               member_ref = new WeakReference (member, false);
-                       }
-
-                       public override bool Equals (object b)
-                       {
-                               ManagerEntry o = (ManagerEntry) b;
-
-                               return (o.source == source && o.member_ref.Target == member_ref.Target);
+                               this.member = member;
                        }
 
                        public override int GetHashCode ()
                        {
-                               return member_hash * source.GetHashCode ();
+                               return source.GetHashCode() ^ member.GetHashCode ();
                        }
 
-                       public override string ToString ()
+                       public override bool Equals (object o)
                        {
-                               return source.ToString () + " + " + (member_ref.Target == null ? " -- null --" : member_ref.Target.ToString ());
+                               HashKey hk = o as HashKey;
+                               if (hk == null)
+                                       return false;
+                               return hk.source == source && hk.member == member;
                        }
                }
 
@@ -79,48 +68,63 @@ namespace System.Windows.Forms {
                }
 
                public bool IsReadOnly {
-                       get {
-                               return false;
-                       }
+                       get { return false; }
                }
 
                public BindingManagerBase this [object dataSource] {
-                       get {
-                               return this [dataSource, String.Empty];
-                       }
+                       get { return this [dataSource, String.Empty]; }
                }
 
                public BindingManagerBase this [object data_source, string data_member] {
                        get {
-                               ManagerEntry e = CreateEntry (data_source, data_member);
-                               WeakReference wref = managers [e] as WeakReference;
+                               if (data_source == null)
+                                       throw new ArgumentNullException ("data_source");
+                               if (data_member == null)
+                                       data_member = String.Empty;
+
+                               HashKey key = new HashKey (data_source, data_member);
+                               BindingManagerBase res = managers [key] as BindingManagerBase;
 
-                               if (wref != null && wref.Target != null)
-                                       return wref.Target as BindingManagerBase;
-                               BindingManagerBase res = AddManager (data_source, data_member);
+                               if (res != null)
+                                       return res;
+
+                               res = CreateBindingManager (data_source, data_member);
+                               if (res == null)
+                                       return null;
+                               managers [key] = res;
                                return res;
                        }
                }
 
-               private BindingManagerBase AddManager (object data_source, string data_member)
+               private BindingManagerBase CreateBindingManager (object data_source, string data_member)
                {
-                       BindingManagerBase res = CreateBindingManager (data_source, data_member);
-                       managers [CreateEntry (data_source, data_member)] = new WeakReference (res);
+                       if (data_member == "") {
+                               if (IsListType (data_source.GetType ()))
+                                       return new CurrencyManager (data_source);
+                               else
+                                       return new PropertyManager (data_source);
+                       }
+                       else {
+                               BindingMemberInfo info = new BindingMemberInfo (data_member);
 
-                       return res;
-               }
+                               BindingManagerBase parent_manager = this[data_source, info.BindingPath];
 
-               private BindingManagerBase CreateBindingManager (object data_source, 
-                       string data_member)
-               {
-                       if (data_source is IList || 
-                               data_source is IListSource ||
-                               data_source is IBindingList) {
-                               CurrencyManager res = new CurrencyManager (data_source);
-                               return res;
+                               PropertyDescriptor pd = parent_manager == null ? null : parent_manager.GetItemProperties ().Find (info.BindingField, true);
+
+                               if (pd == null)
+                                       throw new ArgumentException (String.Format ("Cannot create a child list for field {0}.", info.BindingField));
+
+                               if (IsListType (pd.PropertyType))
+                                       return new RelatedCurrencyManager (parent_manager, pd);
+                               else
+                                       return new RelatedPropertyManager (parent_manager, info.BindingField);
                        }
+               }
 
-                       return new PropertyManager (data_source, data_member);
+               bool IsListType (Type t)
+               {
+                       return (typeof (IList).IsAssignableFrom (t)
+                               || typeof (IListSource).IsAssignableFrom (t));
                }
 
                #region Public Instance Methods
@@ -131,9 +135,13 @@ namespace System.Windows.Forms {
 
                public bool Contains (object dataSource, string dataMember)
                {
-                       ManagerEntry entry = CreateEntry (dataSource, dataMember);
+                       if (dataSource == null)
+                               throw new ArgumentNullException ("dataSource");
+                       if (dataMember == null)
+                               dataMember = String.Empty;
 
-                       return managers.ContainsKey (entry);
+                       HashKey key = new HashKey (dataSource, dataMember);
+                       return managers [key] != null;
                }
                #endregion      // Public Instance Methods
 
@@ -151,7 +159,9 @@ namespace System.Windows.Forms {
                                throw new ArgumentNullException ("dataSource");
                        if (listManager == null)
                                throw new ArgumentNullException ("listManager");
-                       managers.Add (CreateEntry (dataSource, String.Empty), new WeakReference (listManager));
+
+                       HashKey key = new HashKey (dataSource, String.Empty);
+                       managers [key] = listManager;
                }
 
                protected internal void Clear ()
@@ -165,27 +175,43 @@ namespace System.Windows.Forms {
                        managers.Clear ();
                }
 
-               protected virtual void OnCollectionChanged(System.ComponentModel.CollectionChangeEventArgs ccevent)
+               protected virtual void OnCollectionChanged (CollectionChangeEventArgs ccevent)
                {
-                       if (CollectionChanged != null) {
-                               CollectionChanged (this, ccevent);
+                       if (onCollectionChangedHandler != null) {
+                               onCollectionChangedHandler (this, ccevent);
                        }
                }
 
                protected internal void Remove (object dataSource)
                {
+                       if (dataSource == null)
+                               throw new ArgumentNullException ("dataSource");
+
                        RemoveCore (dataSource);
                        OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataSource));
                }
 
                protected virtual void RemoveCore (object dataSource)
                {
-                       managers.Remove (CreateEntry (dataSource, String.Empty));
+                       HashKey[] keys = new HashKey [managers.Keys.Count];
+                       managers.Keys.CopyTo (keys, 0);
+
+                       for (int i = 0; i < keys.Length; i ++) {
+                               if (keys[i].source == dataSource)
+                                       managers.Remove (keys[i]);
+                       }
                }
                #endregion      // Protected Instance Methods
 
                #region Events
-               public event CollectionChangeEventHandler CollectionChanged;
+#if NET_2_0
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+#endif
+               public event CollectionChangeEventHandler CollectionChanged {
+                       add { throw new NotImplementedException (); }
+                       remove { /* nothing to do here.. */ }
+               }
                #endregion      // Events
 
                #region ICollection Interfaces
@@ -195,35 +221,24 @@ namespace System.Windows.Forms {
                }
 
                int ICollection.Count {
-                       get {
-                               return managers.Count;
-                       }
+                       get { return managers.Count; }
                }
 
                bool ICollection.IsSynchronized {
-                       get {
-                               return false;
-                       }
+                       get { return false; }
                }
 
                object ICollection.SyncRoot {
-                       get {
-                               return null;
-                       }
+                       get { return null; }
                }
 
                #endregion      // ICollection Interfaces
 
                #region IEnumerable Interfaces
-               [MonoTODO]
+               [MonoTODO ("our enumerator is slightly different.  in MS's implementation the Values are WeakReferences to the managers.")]
                IEnumerator IEnumerable.GetEnumerator() {
-                       throw new NotImplementedException();
+                       return managers.GetEnumerator ();
                }
                #endregion      // IEnumerable Interfaces
-
-               private ManagerEntry CreateEntry (object dataSource, string dataMember)
-               {
-                       return new ManagerEntry (dataSource, dataMember);
-               }
        }
 }