2008-03-06 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / BindingContext.cs
index f3a29baead24e4a5a91f8f1e0bd52886df774bd5..cc09f64d346882f5dd9dc7638ddc4b983517da90 100644 (file)
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// Copyright (c) 2004 Novell, Inc.
+// Copyright (c) 2004-2005 Novell, Inc.
 //
 // Authors:
 //     Peter Bartok    pbartok@novell.com
-//
+//     Jackson Harper  jackson@ximian.com
 
-// NOT COMPLETE
 
+using System.Data;
 using System.Collections;
+using System.Globalization;
 using System.ComponentModel;
 
+
 namespace System.Windows.Forms {
+
+       [DefaultEvent("CollectionChanged")]
        public class BindingContext : ICollection, IEnumerable {
-               #region Public Constructors
-               public BindingContext() {
+
+               private Hashtable managers;
+               private EventHandler onCollectionChangedHandler;
+
+               private class HashKey {
+                       public object source;
+                       public string member;
+
+                       public HashKey (object source, string member)
+                       {
+                               this.source = source;
+                               this.member = member;
+                       }
+
+                       public override int GetHashCode ()
+                       {
+                               return source.GetHashCode() ^ member.GetHashCode ();
+                       }
+
+                       public override bool Equals (object o)
+                       {
+                               HashKey hk = o as HashKey;
+                               if (hk == null)
+                                       return false;
+                               return hk.source == source && hk.member == member;
+                       }
+               }
+
+               public BindingContext () 
+               {
+                       managers = new Hashtable ();
                }
-               #endregion      // Public Constructors
 
-               #region Public Instance Properties
-               [MonoTODO]
                public bool IsReadOnly {
-                       get {
-                               throw new NotImplementedException();
-                       }
+                       get { return false; }
                }
 
-               public BindingManagerBase this[object dataSource] {
+               public BindingManagerBase this [object dataSource] {
+                       get { return this [dataSource, String.Empty]; }
+               }
+
+               public BindingManagerBase this [object dataSource, string dataMember] {
                        get {
-                               return this[dataSource, String.Empty];
+                               if (dataSource == null)
+                                       throw new ArgumentNullException ("dataSource");
+                               if (dataMember == null)
+                                       dataMember = String.Empty;
+
+                               HashKey key = new HashKey (dataSource, dataMember);
+                               BindingManagerBase res = managers [key] as BindingManagerBase;
+
+                               if (res != null)
+                                       return res;
+
+                               res = CreateBindingManager (dataSource, dataMember);
+                               if (res == null)
+                                       return null;
+                               managers [key] = res;
+                               return res;
                        }
                }
 
-               [MonoTODO]
-               public BindingManagerBase this[object dataSource, string dataMember] {
-                       get {
-                               throw new NotImplementedException();
+               private BindingManagerBase CreateBindingManager (object data_source, string data_member)
+               {
+                       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);
+
+                               BindingManagerBase parent_manager = this[data_source, info.BindingPath];
+
+                               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);
                        }
                }
 
-               
-               #endregion      // Public Instance Properties
+               bool IsListType (Type t)
+               {
+                       return (typeof (IList).IsAssignableFrom (t)
+                               || typeof (IListSource).IsAssignableFrom (t));
+               }
 
                #region Public Instance Methods
-               public bool Contains(object dataSource) {
-                       return Contains(dataSource, String.Empty);
+               public bool Contains(object dataSource)
+               {
+                       return Contains (dataSource, String.Empty);
                }
 
-               [MonoTODO]
-               public bool Contains(object dataSource, string dataMember) {
-                       throw new NotImplementedException();
+               public bool Contains (object dataSource, string dataMember)
+               {
+                       if (dataSource == null)
+                               throw new ArgumentNullException ("dataSource");
+                       if (dataMember == null)
+                               dataMember = String.Empty;
+
+                       HashKey key = new HashKey (dataSource, dataMember);
+                       return managers [key] != null;
                }
                #endregion      // Public Instance Methods
 
                #region Protected Instance Methods
-               protected internal void Add(object dataSource, BindingManagerBase listManager) {
-                       AddCore(dataSource, listManager);
+
+               protected internal void Add (object dataSource, BindingManagerBase listManager)
+               {
+                       AddCore (dataSource, listManager);
+                       OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataSource));
                }
 
-               [MonoTODO]
-               protected virtual void AddCore(object dataSource, BindingManagerBase listManager) {
-                       throw new NotImplementedException();
+               protected virtual void AddCore (object dataSource, BindingManagerBase listManager)
+               {
+                       if (dataSource == null)
+                               throw new ArgumentNullException ("dataSource");
+                       if (listManager == null)
+                               throw new ArgumentNullException ("listManager");
+
+                       HashKey key = new HashKey (dataSource, String.Empty);
+                       managers [key] = listManager;
                }
 
-               protected internal void Clear() {
+               protected internal void Clear ()
+               {
                        ClearCore();
+                       OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
                }
 
-               [MonoTODO]
-               protected virtual void ClearCore() {
-                       throw new NotImplementedException();
+               protected virtual void ClearCore ()
+               {
+                       managers.Clear ();
                }
 
-               protected virtual void OnCollectionChanged(System.ComponentModel.CollectionChangeEventArgs ccevent) {
-                       if (CollectionChanged!=null) CollectionChanged(this, ccevent);
+               protected virtual void OnCollectionChanged (CollectionChangeEventArgs ccevent)
+               {
+                       if (onCollectionChangedHandler != null) {
+                               onCollectionChangedHandler (this, ccevent);
+                       }
                }
 
-               protected internal void Remove(object dataSource) {
-                       RemoveCore(dataSource);
+               protected internal void Remove (object dataSource)
+               {
+                       if (dataSource == null)
+                               throw new ArgumentNullException ("dataSource");
+
+                       RemoveCore (dataSource);
+                       OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataSource));
                }
 
-               [MonoTODO]
-               protected virtual void RemoveCore(object dataSource) {
-                       throw new NotImplementedException();
+               protected virtual void RemoveCore (object dataSource)
+               {
+                       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
-               [MonoTODO]
-               void ICollection.CopyTo(Array array, int index) {
-                       throw new NotImplementedException();
+               void ICollection.CopyTo (Array array, int index)
+               {
+                       managers.CopyTo (array, index);
                }
 
-               [MonoTODO]
                int ICollection.Count {
-                       get {
-                               throw new NotImplementedException();
-                       }
+                       get { return managers.Count; }
                }
 
                bool ICollection.IsSynchronized {
-                       get {
-                               return false;
-                       }
+                       get { return false; }
                }
 
                object ICollection.SyncRoot {
-                       get {
-                               return this;
-                       }
+                       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
        }