// 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 {
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; }
}
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;
}
}
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);
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.
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);
}
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)
private int AddSorted (TreeNode node)
{
-
if (count >= nodes.Length)
Grow ();
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);
}
}
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;
}
public object Current {
- get { return collection [index]; }
+ get {
+ if (index == -1)
+ return null;
+ return collection [index];
+ }
}
public bool MoveNext ()
public void Reset ()
{
- index = 0;
+ index = -1;
}
}