New tests.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TreeNodeCollection.cs
index 42e81610abb9d4a3b753f713effcfb2373ffcc7a..007fb1ef029e4f426ad89f082548df2a0de34c21 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-2005 Novell, Inc.
+// Copyright (c) 2004-2006 Novell, Inc.
 //
 // Authors:
 //     Jackson Harper (jackson@ximian.com)
 
-// TODO: Sorting
 
 using System;
 using System.Collections;
 using System.ComponentModel;
 using System.Globalization;
 
+#if NET_2_0
+using System.Collections.Generic;
+#endif
+
 namespace System.Windows.Forms {
        [Editor("System.Windows.Forms.Design.TreeNodeCollectionEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
        public class TreeNodeCollection : IList, ICollection, IEnumerable {
@@ -49,13 +52,15 @@ namespace System.Windows.Forms {
                        nodes = new TreeNode [OrigSize];
                }
 
-               [Browsable(false)]
+#if !NET_2_0
                [EditorBrowsable(EditorBrowsableState.Advanced)]
-               public virtual int Count {
+#endif
+               [Browsable(false)]
+               public int Count {
                        get { return count; }
                }
 
-               public virtual bool IsReadOnly {
+               public bool IsReadOnly {
                        get { return false; }
                }
 
@@ -73,16 +78,12 @@ namespace System.Windows.Forms {
 
                object IList.this [int index] {
                        get {
-                               if (index < 0 || index >= Count)
-                                       throw new ArgumentOutOfRangeException ("index");
-                               return nodes [index];
+                               return this [index];
                        }
                        set {
-                               if (index < 0 || index >= Count)
-                                       throw new ArgumentOutOfRangeException ("index");
-                               TreeNode node = (TreeNode) value;
-                               node.parent = owner;
-                               nodes [index] = node;
+                               if (!(value is TreeNode))
+                                       throw new ArgumentException ("Parameter must be of type TreeNode.", "value");
+                               this [index] = (TreeNode) value;
                        }
                }
 
@@ -95,11 +96,23 @@ namespace System.Windows.Forms {
                        set {
                                if (index < 0 || index >= Count)
                                        throw new ArgumentOutOfRangeException ("index");
-                               value.parent = owner;
+                               SetupNode (value);
                                nodes [index] = value;
                        }
                }
 
+#if NET_2_0
+               public virtual TreeNode this [string key] {
+                       get {
+                               for (int i = 0; i < count; i++)
+                                       if (string.Compare (key, nodes[i].Name, true) == 0)
+                                               return nodes[i];
+                                               
+                               return null;
+                       }
+               }
+#endif
+
                public virtual TreeNode Add (string text)
                {
                        TreeNode res = new TreeNode (text);
@@ -112,30 +125,78 @@ namespace System.Windows.Forms {
                        if (node == null)
                                throw new ArgumentNullException("node");
 
-                       // Remove it from any old parents
-                       node.Remove ();
+                       int res;
+                       TreeView tree_view = null;
+
+                       if (owner != null)
+                               tree_view = owner.TreeView;
+                               
+                       if (tree_view != null && tree_view.Sorted) {
+                               res = AddSorted (node);
+                       } else {
+                               if (count >= nodes.Length)
+                                       Grow ();
+                               nodes[count] = node;
+                               res = count;
+                               count++;
+                       }
 
-                       if (owner != null && owner.TreeView != null && owner.TreeView.Sorted)
-                               return AddSorted (node);
-                       node.parent = owner;
-                       if (count >= nodes.Length)
-                               Grow ();
-                       nodes [count++] = node;
+                       SetupNode (node);
+#if NET_2_0
+                       // UIA Framework Event: Collection Changed
+                       if (tree_view != null)
+                               tree_view.OnUIACollectionChanged (owner, new CollectionChangeEventArgs (CollectionChangeAction.Add, node));
+#endif
+                       return res;
+               }
 
-                       if (owner.TreeView != null && (owner.IsExpanded || owner.IsRoot)) {
-                               // XXX: Need to ensure the boxes for the nodes have been created
-                               owner.TreeView.UpdateNode (owner);
-                       } else if (owner.TreeView != null) {
-                               owner.TreeView.UpdateNodePlusMinus (owner);
-                       }
+#if NET_2_0
+               public virtual TreeNode Add (string key, string text)
+               {
+                       TreeNode node = new TreeNode (text);
+                       node.Name = key;
+                       Add (node);
+                       return node;
+               }
 
-                       return count;
+               public virtual TreeNode Add (string key, string text, int imageIndex)
+               {
+                       TreeNode node = Add (key, text);
+                       node.ImageIndex = imageIndex;
+                       return node;
+               }
+
+               public virtual TreeNode Add (string key, string text, string imageKey)
+               {
+                       TreeNode node = Add (key, text);
+                       node.ImageKey = imageKey;
+                       return node;
+
+               }
+
+               public virtual TreeNode Add (string key, string text, int imageIndex, int selectedImageIndex)
+               {
+                       TreeNode node = Add (key, text);
+                       node.ImageIndex = imageIndex;
+                       node.SelectedImageIndex = selectedImageIndex;
+                       return node;
                }
 
+               public virtual TreeNode Add (string key, string text, string imageKey, string selectedImageKey)
+               {
+                       TreeNode node = Add (key, text);
+                       node.ImageKey = imageKey;
+                       node.SelectedImageKey = selectedImageKey;
+                       return node;
+               }
+
+
+#endif
+
                public virtual void AddRange (TreeNode [] nodes)
                {
                        if (nodes == null)
-                               throw new ArgumentNullException("node");
+                               throw new ArgumentNullException("nodes");
 
                        // We can't just use Array.Copy because the nodes also
                        // need to have some properties set when they are added.
@@ -145,24 +206,44 @@ namespace System.Windows.Forms {
 
                public virtual void Clear ()
                {
+                       while (count > 0)
+                               RemoveAt (0, false);
+                       
                        Array.Clear (nodes, 0, count);
                        count = 0;
 
-                       if (owner.TreeView != null)
-                               owner.TreeView.UpdateBelow (owner);
+                       TreeView tree_view = null;
+                       if (owner != null) {
+                               tree_view = owner.TreeView;
+                               if (tree_view != null) {
+                                       tree_view.UpdateBelow (owner);
+                                       tree_view.RecalculateVisibleOrder (owner);
+                                       tree_view.UpdateScrollBars (false);
+                               }
+                       }
                }
 
                public bool Contains (TreeNode node)
                {
-                       return (Array.BinarySearch (nodes, node) > 0);
+                       return Array.IndexOf (nodes, node, 0, count) != -1;
+               }
+#if NET_2_0
+               public virtual bool ContainsKey (string key)
+               {
+                       for (int i = 0; i < count; i++) {
+                               if (string.Compare (nodes [i].Name, key, true, CultureInfo.InvariantCulture) == 0)
+                                       return true;
+                       }
+                       return false;
                }
+#endif
 
-               public virtual void CopyTo (Array dest, int index)
+               public void CopyTo (Array dest, int index)
                {
-                       nodes.CopyTo (dest, index);
+                       Array.Copy (nodes, index, dest, index, count);
                }
 
-               public virtual IEnumerator GetEnumerator ()
+               public IEnumerator GetEnumerator ()
                {
                        return new TreeNodeEnumerator (this);
                }
@@ -172,37 +253,207 @@ namespace System.Windows.Forms {
                        return Array.IndexOf (nodes, node);
                }
 
-               public virtual void Insert (int index, TreeNode node)
+#if NET_2_0
+               public virtual int IndexOfKey (string key)
                {
-                       node.parent = owner;
+                       for (int i = 0; i < count; i++) {
+                               if (string.Compare (nodes [i].Name, key, true, CultureInfo.InvariantCulture) == 0)
+                                       return i;
+                       }
+                       return -1;
+               }
+               
+               public virtual TreeNode Insert (int index, string text)
+               {
+                       TreeNode node = new TreeNode (text);
+                       Insert (index, node);
+                       return node;
+               }
+#endif
 
+               public virtual void Insert (int index, TreeNode node)
+               {
                        if (count >= nodes.Length)
                                Grow ();
 
                        Array.Copy (nodes, index, nodes, index + 1, count - index);
                        nodes [index] = node;
                        count++;
+
+                       SetupNode (node);
                }
 
+#if NET_2_0
+               public virtual TreeNode Insert (int index, string key, string text)
+               {
+                       TreeNode node = new TreeNode (text);
+                       node.Name = key;
+                       Insert (index, node);
+                       return node;
+               }
+
+               public virtual TreeNode Insert (int index, string key, string text, int imageIndex)
+               {
+                       TreeNode node = new TreeNode (text);
+                       node.Name = key;
+                       node.ImageIndex = imageIndex;
+                       Insert (index, node);
+                       return node;
+               }
+
+               public virtual TreeNode Insert (int index, string key, string text, string imageKey)
+               {
+                       TreeNode node = new TreeNode (text);
+                       node.Name = key;
+                       node.ImageKey = imageKey;
+                       Insert (index, node);
+                       return node;
+               }
+
+               public virtual TreeNode Insert (int index, string key, string text, int imageIndex, int selectedImageIndex)
+               {
+                       TreeNode node = new TreeNode (text, imageIndex, selectedImageIndex);
+                       node.Name = key;
+                       Insert (index, node);
+                       return node;
+               }
+
+               public virtual TreeNode Insert (int index, string key, string text, string imageKey, string selectedImageKey)
+               {
+                       TreeNode node = new TreeNode (text);
+                       node.Name = key;
+                       node.ImageKey = imageKey;
+                       node.SelectedImageKey = selectedImageKey;
+                       Insert (index, node);
+                       return node;
+               }
+#endif
+
                public void Remove (TreeNode node)
                {
+                       if (node == null)
+                               throw new NullReferenceException ();
+
                        int index = IndexOf (node);
-                       if (index > 0)
+                       if (index != -1)
                                RemoveAt (index);
+#if ONLY_1_1
+                       else
+                               throw new NullReferenceException ();
+#endif
                }
 
                public virtual void RemoveAt (int index)
+               {
+                       RemoveAt (index, true);
+               }
+
+               private void RemoveAt (int index, bool update)
                {
                        TreeNode removed = nodes [index];
-                       TreeNode parent = removed.parent;
-                       removed.parent = null;
+                       TreeNode prev = GetPrevNode (removed);
+                       TreeNode new_selected = null;
+                       bool re_set_selected = false;
+                       bool visible = removed.IsVisible;
+
+                       TreeView tree_view = null;
+                       if (owner != null)
+                               tree_view = owner.TreeView;
+
+                       if (tree_view != null) {
+                               tree_view.RecalculateVisibleOrder (prev);
+
+                               if (removed == tree_view.SelectedNode) {
+                                       re_set_selected = true;
+                                       OpenTreeNodeEnumerator oe = new OpenTreeNodeEnumerator (removed);
+                                       if (oe.MoveNext () && oe.MoveNext ()) {
+                                               new_selected = oe.CurrentNode;
+                                       } else {
+                                               oe = new OpenTreeNodeEnumerator (removed);
+                                               oe.MovePrevious ();
+                                               new_selected = oe.CurrentNode == removed ? null : oe.CurrentNode;
+                                       }
+                               }
+                       }
 
-                       Array.Copy (nodes, index + 1, nodes, index, count - index);
+                       Array.Copy (nodes, index + 1, nodes, index, count - index - 1);
                        count--;
+                       
+                       nodes[count] = null;
+                       
                        if (nodes.Length > OrigSize && nodes.Length > (count * 2))
                                Shrink ();
-                       if (owner.TreeView != null)
-                               owner.TreeView.UpdateBelow (parent);
+
+                       if (tree_view != null && re_set_selected) {
+                               tree_view.SelectedNode = new_selected;
+                       }
+
+                       TreeNode parent = removed.parent;
+                       removed.parent = null;
+
+                       if (update && tree_view != null && visible) {
+                               tree_view.RecalculateVisibleOrder (prev);
+                               tree_view.UpdateScrollBars (false);
+                               tree_view.UpdateBelow (parent);
+                       }
+#if NET_2_0
+                       // UIA Framework Event: Collection Changed
+                       if (tree_view != null)
+                               tree_view.OnUIACollectionChanged (owner, new CollectionChangeEventArgs (CollectionChangeAction.Remove, removed));
+#endif
+               }
+
+#if NET_2_0
+               public virtual void RemoveByKey (string key)
+               {
+                       TreeNode node = this[key];
+                       
+                       if (node != null)
+                               Remove (node);
+               }
+#endif
+
+               private TreeNode GetPrevNode (TreeNode node)
+               {
+                       OpenTreeNodeEnumerator one = new OpenTreeNodeEnumerator (node);
+
+                       if (one.MovePrevious () && one.MovePrevious ())
+                               return one.CurrentNode;
+                       return null;
+               }
+
+               private void SetupNode (TreeNode node)
+               {
+                       // Remove it from any old parents
+                       node.Remove ();
+
+                       node.parent = owner;
+
+                       TreeView tree_view = null;
+                       if (owner != null)
+                               tree_view = owner.TreeView;
+
+                       if (tree_view != null) {
+                               bool sorted = false;
+                               if (tree_view.Sorted || tree_view.TreeViewNodeSorter != null) {
+                                       owner.Nodes.Sort (tree_view.TreeViewNodeSorter);
+                                       tree_view.sorted = sorted = true;
+                               }
+
+                               // We may need to invalidate this entire node collection if sorted.
+                               TreeNode prev = sorted ? owner : GetPrevNode (node);
+
+                               if (tree_view.IsHandleCreated && node.ArePreviousNodesExpanded)
+                                       tree_view.RecalculateVisibleOrder (prev);
+                               if (owner == tree_view.root_node || node.Parent.IsVisible && node.Parent.IsExpanded)
+                                       tree_view.UpdateScrollBars (false);
+                       }
+
+                       if (owner != null && tree_view != null && (owner.IsExpanded || owner.IsRoot)) {
+                                tree_view.UpdateBelow (owner);
+                       } else if (owner != null && tree_view != null) {
+                               tree_view.UpdateBelow (owner);
+                       }
                }
 
                int IList.Add (object node)
@@ -232,7 +483,6 @@ namespace System.Windows.Forms {
 
                private int AddSorted (TreeNode node)
                {
-                       
                        if (count >= nodes.Length)
                                Grow ();
 
@@ -259,17 +509,15 @@ namespace System.Windows.Forms {
                        count++;
                        nodes [pos] = node;
 
-                       node.parent = owner;
                        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));
+               internal void Sort (IComparer sorter) {
+                       Array.Sort (nodes, 0, count, sorter == null ? new TreeNodeComparer (Application.CurrentCulture.CompareInfo) : sorter);
 
                        for (int i = 0; i < count; i++) {
-                               nodes [i].Nodes.Sort ();
+                               nodes [i].Nodes.Sort (sorter);
                        }
                }
 
@@ -282,13 +530,42 @@ namespace System.Windows.Forms {
 
                private void Shrink ()
                {
-                       int len = (count > OrigSize ? count : OrigSize);
+                       int len = (count + 1 > OrigSize ? count + 1 : OrigSize);
                        TreeNode [] nn = new TreeNode [len];
                        Array.Copy (nodes, nn, count);
                        nodes = nn;
                }
 
+#if NET_2_0
+               public TreeNode[] Find (string key, bool searchAllChildren)
+               {
+                       List<TreeNode> results = new List<TreeNode> (0);
+                       Find (key, searchAllChildren, this, results);
+
+                       return results.ToArray ();             
+               }
                
+               private static void Find (string key, bool searchAllChildren, TreeNodeCollection nodes, List<TreeNode> results)
+               {
+                       for (int i = 0; i < nodes.Count; i++) {
+                               TreeNode thisNode = nodes [i];
+                               
+                               if (string.Compare (thisNode.Name, key, true, CultureInfo.InvariantCulture) == 0) 
+                                       results.Add (thisNode);
+
+                       }
+                       // Need to match the Microsoft order.
+
+                       if (searchAllChildren){
+                               for (int i = 0; i < nodes.Count; i++){
+                                       TreeNodeCollection childNodes = nodes [i].Nodes;
+                                       if (childNodes.Count > 0) {
+                                               Find (key, searchAllChildren, childNodes, results);
+                                       }
+                               }
+                       }
+               }
+#endif
                internal class TreeNodeEnumerator : IEnumerator {
 
                        private TreeNodeCollection collection;
@@ -300,7 +577,11 @@ namespace System.Windows.Forms {
                        }
 
                        public object Current {
-                               get { return collection [index]; }
+                               get {
+                                       if (index == -1)
+                                               return null;
+                                       return collection [index];
+                               }
                        }
 
                        public bool MoveNext ()
@@ -313,7 +594,7 @@ namespace System.Windows.Forms {
 
                        public void Reset ()
                        {
-                               index = 0;
+                               index = -1;
                        }
                }