2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TreeNodeCollection.cs
index e2761a2d89079b74d27eb13ad1633317efa50d97..94a34ad22581d8be5da800b9804a4a88d2a0cbe4 100644 (file)
@@ -1,6 +1,3 @@
-//
-// System.Windows.Forms.TreeNode.cs
-//
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // "Software"), to deal in the Software without restriction, including
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// Autors:
-//             Marek Safar             marek.safar@seznam.cz
-//
-//
-//
+// Copyright (c) 2004 Novell, Inc.
 //
+// Authors:
+//     Jackson Harper (jackson@ximian.com)
 
-// NOT COMPLETE
+// TODO: Sorting
 
 using System;
 using System.Collections;
+using System.Globalization;
+
+namespace System.Windows.Forms {
 
-namespace System.Windows.Forms
-{
-       public class TreeNodeCollection: ICollection, IEnumerable, IList
-       {
-               TreeNode owner;
+       public class TreeNodeCollection : IList, ICollection, IEnumerable {
 
-               ArrayList collection = new ArrayList ();
+               private static readonly int OrigSize = 50;
+
+               private TreeNode owner;
+               private int count;
+               private TreeNode [] nodes;
+
+               private TreeNodeCollection ()
+               {
+               }
 
                internal TreeNodeCollection (TreeNode owner)
                {
                        this.owner = owner;
+                       nodes = new TreeNode [OrigSize];
                }
 
-        [MonoTODO ("Check implementation")]
-               public virtual int Add (TreeNode node)
-               {
-                       if (node == null)
-                               throw new ArgumentNullException("value");
+               public virtual int Count {
+                       get { return count; }
+               }
 
-                       if (node.Parent != null)
-                               throw new ArgumentException("Object already has a parent", "node");
+               public virtual bool IsReadOnly {
+                       get { return false; }
+               }
 
-                       node.SetParent (owner);
-                       int index = collection.Add (node);
-                       node.SetIndex (index);
-                       return index;           
+               bool ICollection.IsSynchronized {
+                       get { return false; }
                }
 
-               public virtual void AddRange (TreeNode[] nodes)
-               {
-                       if (nodes == null)
-                               throw new ArgumentNullException("nodes");
+               object ICollection.SyncRoot {
+                       get { return this; }
+               }
 
-                       foreach (TreeNode node in nodes) {
-                               Add (node);
-                       }
+               bool IList.IsFixedSize {
+                       get { return false; }
                }
 
-               public int Count {
+               object IList.this [int index] {
                        get {
-                               return collection.Count;
+                               if (index < 0 || index > Count)
+                                       throw new ArgumentOutOfRangeException ("index");
+                               return nodes [index];
+                       }
+                       set {
+                               if (index < 0 || index > Count)
+                                       throw new ArgumentOutOfRangeException ("index");
+                               TreeNode node = (TreeNode) value;
+                               SetData (node);
+                               nodes [index] = node;
                        }
                }
 
-               [MonoTODO ("set")]
                public virtual TreeNode this [int index] {
                        get {
-                               return (TreeNode)collection [index];
+                               if (index < 0 || index > Count)
+                                       throw new ArgumentOutOfRangeException ("index");
+                               return nodes [index];
                        }
                        set {
-                               throw new NotImplementedException ();
+                               if (index < 0 || index > Count)
+                                       throw new ArgumentOutOfRangeException ("index");
+                               SetData (value);
+                               nodes [index] = value;
                        }
                }
-       
-               #region IEnumerable Members
 
-               public IEnumerator GetEnumerator ()
+               public virtual TreeNode Add (string text)
                {
-                       return collection.GetEnumerator ();
+                       TreeNode res = new TreeNode (text);
+                       Add (res);
+                       return res;
                }
 
-               #endregion
-       
-               #region ICollection Members
+               public virtual int Add (TreeNode node)
+               {
+                       if (node == null)
+                               throw new ArgumentNullException("node");
 
-               bool ICollection.IsSynchronized {
-                       get {
-                               return false;
-                       }
+                       if (owner != null && owner.TreeView != null && owner.TreeView.Sorted)
+                               return AddSorted (node);
+                       SetData (node);
+                       if (count >= nodes.Length)
+                               Grow ();
+                       nodes [count++] = node;
+
+                       if (owner.TreeView != null)
+                               owner.TreeView.Refresh ();
+                       return count;
                }
 
-               public void CopyTo(Array array, int index)
+               public virtual void AddRange (TreeNode [] nodes)
                {
-                       collection.CopyTo (array, index);
+                       if (nodes == null)
+                               throw new ArgumentNullException("node");
+
+                       // We can't just use Array.Copy because the nodes also
+                       // need to have some properties set when they are added.
+                       for (int i = 0; i < nodes.Length; i++)
+                               Add (nodes [i]);
                }
 
-               object ICollection.SyncRoot {
-                       get {
-                               return this;
-                       }
+               public virtual void Clear ()
+               {
+                       Array.Clear (nodes, 0, count);
+                       count = 0;
                }
 
-               #endregion
+               public bool Contains (TreeNode node)
+               {
+                       return (Array.BinarySearch (nodes, node) > 0);
+               }
 
-               #region IList Members
+               public virtual void CopyTo (Array dest, int index)
+               {
+                       nodes.CopyTo (dest, index);
+               }
 
-               public bool IsReadOnly {
-                       get {
-                               return false;
-                       }
+               public virtual IEnumerator GetEnumerator ()
+               {
+                       return new TreeNodeEnumerator (this);
                }
 
-               [MonoTODO]
-               object IList.this[int index] {
-                       get {
-                               return null;
-                       }
-                       set {
-                       }
+               public int IndexOf (TreeNode node)
+               {
+                       return Array.IndexOf (nodes, node);
                }
 
-               public void RemoveAt (int index)
+               public virtual void Insert (int index, TreeNode node)
                {
-                       collection.RemoveAt (index);
+                       SetData (node);
+                       IList list = (IList) nodes;
+                       list.Insert (index, node);
                }
 
-               [MonoTODO]
-               void IList.Insert(int index, object value)
-        {
+               public virtual void Remove (TreeNode node)
+               {
+                       int index = IndexOf (node);
+                       if (index > 0)
+                               RemoveAt (index);
                }
 
-               [MonoTODO]
-               void IList.Remove(object value)
+               public virtual void RemoveAt (int index)
                {
+                       Array.Copy (nodes, index, nodes, index - 1, count - index);
+                       count--;
+                       if (nodes.Length > OrigSize && nodes.Length > (count * 2))
+                               Shrink ();
+                       if (owner.TreeView != null)
+                               owner.TreeView.TotalNodeCount--;
                }
-                
-               [MonoTODO]
-               bool IList.Contains(object value)
+
+               int IList.Add (object node)
                {
-                       return false;
+                       return Add ((TreeNode) node);
                }
 
-               public void Clear()
+               bool IList.Contains (object node)
                {
-                       collection.Clear ();
+                       return Contains ((TreeNode) node);
+               }
+               
+               int IList.IndexOf (object node)
+               {
+                       return IndexOf ((TreeNode) node);
                }
 
-               [MonoTODO]
-               int IList.IndexOf(object value)
+               void IList.Insert (int index, object node)
                {
-                       return 0;
+                       Insert (index, (TreeNode) node);
                }
 
-               [MonoTODO]
-               int IList.Add(object value)
+               void IList.Remove (object node)
                {
-                       return 0;
+                       Remove ((TreeNode) node);
                }
 
-               public bool IsFixedSize {
-                       get {
-                               return false;
+               private int AddSorted (TreeNode node)
+               {
+                       
+                       if (count >= nodes.Length)
+                               Grow ();
+
+                       CompareInfo compare = Application.CurrentCulture.CompareInfo;
+                       int pos = 0;
+                       bool found = false;
+                       for (int i = 0; i < count; i++) {
+                               pos = i;
+                               int comp = compare.Compare (node.Text, nodes [i].Text);
+                               if (comp < 0) {
+                                       found = true;
+                                       break;
+                               }
+                       }
+
+                       // Stick it at the end
+                       if (!found)
+                               pos = count;
+
+                       // Move the nodes up and adjust their indices
+                       for (int i = count - 1; i >= pos; i--) {
+                               nodes [i + 1] = nodes [i];
+                               nodes [i + 1].SetIndex (i + 1);
+                       }
+                       count++;
+                       nodes [pos] = node;
+
+                       SetData (node, pos);
+                       return count;
+               }
+
+               // Would be nice to do this without running through the collection twice
+               internal void Sort () {
+
+                       Array.Sort (nodes, 0, count, new TreeNodeComparer (Application.CurrentCulture.CompareInfo));
+
+                       for (int i = 0; i < count; i++) {
+                               nodes [i].SetIndex (i);
+                               nodes [i].Nodes.Sort ();
+                       }
+               }
+
+               private void SetData (TreeNode node)
+               {
+                       SetData (node, count);
+               }
+
+               private void SetData (TreeNode node, int pos)
+               {
+                       node.SetAddedData ((owner != null ? owner.TreeView : null), owner, pos);
+               }
+
+               private void Grow ()
+               {
+                       TreeNode [] nn = new TreeNode [nodes.Length + 50];
+                       Array.Copy (nodes, nn, nodes.Length);
+                       nodes = nn;
+               }
+
+               private void Shrink ()
+               {
+                       int len = (count > OrigSize ? count : OrigSize);
+                       TreeNode [] nn = new TreeNode [len];
+                       Array.Copy (nodes, nn, count);
+                       nodes = nn;
+               }
+
+               
+               internal class TreeNodeEnumerator : IEnumerator {
+
+                       private TreeNodeCollection collection;
+                       private int index = -1;
+
+                       public TreeNodeEnumerator (TreeNodeCollection collection)
+                       {
+                               this.collection = collection;
+                       }
+
+                       public object Current {
+                               get { return collection [index]; }
+                       }
+
+                       public bool MoveNext ()
+                       {
+                               if (index + 1 >= collection.Count)
+                                       return false;
+                               index++;
+                               return true;
+                       }
+
+                       public void Reset ()
+                       {
+                               index = 0;
                        }
                }
 
-               #endregion
+               private class TreeNodeComparer : IComparer {
+
+                       private CompareInfo compare;
+               
+                       public TreeNodeComparer (CompareInfo compare)
+                       {
+                               this.compare = compare;
+                       }
+               
+                       public int Compare (object x, object y)
+                       {
+                               TreeNode l = (TreeNode) x;
+                               TreeNode r = (TreeNode) y;
+                               int res = compare.Compare (l.Text, r.Text);
+
+                               return (res == 0 ? l.Index - r.Index : res);
+                       }
+               }
        }
 }
+