| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- // 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
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // 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-2006 Novell, Inc.
- //
- // Authors:
- // Jackson Harper ([email protected])
- using System;
- using System.Collections;
- using System.ComponentModel;
- using System.Globalization;
- namespace System.Windows.Forms {
- [Editor("System.Windows.Forms.Design.TreeNodeCollectionEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
- public class TreeNodeCollection : IList, ICollection, IEnumerable {
- 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];
- }
- [Browsable(false)]
- [EditorBrowsable(EditorBrowsableState.Advanced)]
- public int Count {
- get { return count; }
- }
- public bool IsReadOnly {
- get { return false; }
- }
- bool ICollection.IsSynchronized {
- get { return false; }
- }
- object ICollection.SyncRoot {
- get { return this; }
- }
- bool IList.IsFixedSize {
- get { return false; }
- }
- object IList.this [int index] {
- get {
- 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;
- SetupNode (node);
- nodes [index] = node;
- }
- }
- public virtual TreeNode this [int index] {
- get {
- if (index < 0 || index >= Count)
- throw new ArgumentOutOfRangeException ("index");
- return nodes [index];
- }
- set {
- if (index < 0 || index >= Count)
- throw new ArgumentOutOfRangeException ("index");
- SetupNode (value);
- nodes [index] = value;
- }
- }
- public virtual TreeNode Add (string text)
- {
- TreeNode res = new TreeNode (text);
- Add (res);
- return res;
- }
- public virtual int Add (TreeNode node)
- {
- if (node == null)
- throw new ArgumentNullException("node");
- int res;
- TreeView tree_view = null;
- if (tree_view != null && tree_view.Sorted) {
- res = AddSorted (node);
- } else {
- if (count >= nodes.Length)
- Grow ();
- nodes [count++] = node;
- res = count;
- }
- SetupNode (node);
- return res;
- }
- public virtual void AddRange (TreeNode [] nodes)
- {
- 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]);
- }
- public virtual void Clear ()
- {
- while (count > 0)
- RemoveAt (0, false);
-
- Array.Clear (nodes, 0, count);
- count = 0;
- TreeView tree_view = null;
- if (owner != null) {
- tree_view = owner.TreeView;
- if (owner.IsRoot)
- tree_view.top_node = null;
- if (tree_view != null) {
- tree_view.UpdateBelow (owner);
- tree_view.RecalculateVisibleOrder (owner);
- }
- }
- }
- public bool Contains (TreeNode node)
- {
- return (Array.BinarySearch (nodes, node) > 0);
- }
- public void CopyTo (Array dest, int index)
- {
- Array.Copy (nodes, index, dest, index, count);
- }
- public IEnumerator GetEnumerator ()
- {
- return new TreeNodeEnumerator (this);
- }
- public int IndexOf (TreeNode node)
- {
- return Array.IndexOf (nodes, node);
- }
- 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);
- }
- public void Remove (TreeNode node)
- {
- if (node == null)
- throw new NullReferenceException ();
- int index = IndexOf (node);
- 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 prev = GetPrevNode (removed);
- TreeNode new_selected = null;
- 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.top_node) {
- if (removed.IsRoot) {
- tree_view.top_node = null;
- } else {
- OpenTreeNodeEnumerator oe = new OpenTreeNodeEnumerator (removed);
- if (oe.MovePrevious () && oe.MovePrevious ()) {
- tree_view.top_node = oe.CurrentNode;
- } else {
- removed.is_expanded = false;
- oe = new OpenTreeNodeEnumerator (removed);
- if (oe.MoveNext () && oe.MoveNext ()) {
- tree_view.top_node = oe.CurrentNode;
- } else {
- tree_view.top_node = null;
- }
- }
- }
- }
- if (removed == tree_view.selected_node) {
- 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;
- }
- }
- }
- Array.Copy (nodes, index + 1, nodes, index, count - index);
- count--;
- if (nodes.Length > OrigSize && nodes.Length > (count * 2))
- Shrink ();
- if (tree_view != null && new_selected != null) {
- 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 ();
- tree_view.UpdateBelow (parent);
- }
- }
- 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) {
- TreeNode prev = GetPrevNode (node);
- if (tree_view.top_node == null)
- tree_view.top_node = node;
- if (node.IsVisible)
- tree_view.RecalculateVisibleOrder (prev);
- if (owner == tree_view.root_node || node.Parent.IsVisible && node.Parent.IsExpanded)
- tree_view.UpdateScrollBars ();
- }
- if (owner != null && tree_view != null && (owner.IsExpanded || owner.IsRoot)) {
- // tree_view.UpdateBelow (owner);
- tree_view.UpdateNode (owner);
- tree_view.UpdateNode (node);
- } else if (owner != null && tree_view != null) {
- tree_view.UpdateBelow (owner);
- }
- }
- int IList.Add (object node)
- {
- return Add ((TreeNode) node);
- }
- bool IList.Contains (object node)
- {
- return Contains ((TreeNode) node);
- }
-
- int IList.IndexOf (object node)
- {
- return IndexOf ((TreeNode) node);
- }
- void IList.Insert (int index, object node)
- {
- Insert (index, (TreeNode) node);
- }
- void IList.Remove (object node)
- {
- Remove ((TreeNode) node);
- }
- 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];
- }
- count++;
- nodes [pos] = node;
- 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].Nodes.Sort ();
- }
- }
- private void Grow ()
- {
- TreeNode [] nn = new TreeNode [nodes.Length + 50];
- Array.Copy (nodes, nn, nodes.Length);
- nodes = nn;
- }
- private void Shrink ()
- {
- int len = (count + 1 > OrigSize ? count + 1 : 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 {
- if (index == -1)
- return null;
- return collection [index];
- }
- }
- public bool MoveNext ()
- {
- if (index + 1 >= collection.Count)
- return false;
- index++;
- return true;
- }
- public void Reset ()
- {
- index = -1;
- }
- }
- 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);
- }
- }
- }
- }
|