1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004-2006 Novell, Inc.
23 // Jackson Harper (jackson@ximian.com)
27 using System.Collections;
28 using System.ComponentModel;
29 using System.Globalization;
32 using System.Collections.Generic;
35 namespace System.Windows.Forms {
36 [Editor("System.Windows.Forms.Design.TreeNodeCollectionEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
37 public class TreeNodeCollection : IList, ICollection, IEnumerable {
39 private static readonly int OrigSize = 50;
41 private TreeNode owner;
43 private TreeNode [] nodes;
45 private TreeNodeCollection ()
49 internal TreeNodeCollection (TreeNode owner)
52 nodes = new TreeNode [OrigSize];
56 [EditorBrowsable(EditorBrowsableState.Advanced)]
63 public bool IsReadOnly {
67 bool ICollection.IsSynchronized {
71 object ICollection.SyncRoot {
75 bool IList.IsFixedSize {
79 object IList.this [int index] {
84 if (!(value is TreeNode))
85 throw new ArgumentException ("Parameter must be of type TreeNode.", "value");
86 this [index] = (TreeNode) value;
90 public virtual TreeNode this [int index] {
92 if (index < 0 || index >= Count)
93 throw new ArgumentOutOfRangeException ("index");
97 if (index < 0 || index >= Count)
98 throw new ArgumentOutOfRangeException ("index");
100 nodes [index] = value;
105 public virtual TreeNode this [string key] {
107 for (int i = 0; i < count; i++)
108 if (string.Compare (key, nodes[i].Name, true) == 0)
116 public virtual TreeNode Add (string text)
118 TreeNode res = new TreeNode (text);
123 public virtual int Add (TreeNode node)
126 throw new ArgumentNullException("node");
129 TreeView tree_view = null;
132 tree_view = owner.TreeView;
134 if (tree_view != null && tree_view.Sorted) {
135 res = AddSorted (node);
137 if (count >= nodes.Length)
146 // UIA Framework Event: Collection Changed
147 if (tree_view != null)
148 tree_view.OnUIACollectionChanged (owner, new CollectionChangeEventArgs (CollectionChangeAction.Add, node));
154 public virtual TreeNode Add (string key, string text)
156 TreeNode node = new TreeNode (text);
162 public virtual TreeNode Add (string key, string text, int imageIndex)
164 TreeNode node = Add (key, text);
165 node.ImageIndex = imageIndex;
169 public virtual TreeNode Add (string key, string text, string imageKey)
171 TreeNode node = Add (key, text);
172 node.ImageKey = imageKey;
177 public virtual TreeNode Add (string key, string text, int imageIndex, int selectedImageIndex)
179 TreeNode node = Add (key, text);
180 node.ImageIndex = imageIndex;
181 node.SelectedImageIndex = selectedImageIndex;
185 public virtual TreeNode Add (string key, string text, string imageKey, string selectedImageKey)
187 TreeNode node = Add (key, text);
188 node.ImageKey = imageKey;
189 node.SelectedImageKey = selectedImageKey;
196 public virtual void AddRange (TreeNode [] nodes)
199 throw new ArgumentNullException("nodes");
201 // We can't just use Array.Copy because the nodes also
202 // need to have some properties set when they are added.
203 for (int i = 0; i < nodes.Length; i++)
207 public virtual void Clear ()
212 Array.Clear (nodes, 0, count);
215 TreeView tree_view = null;
217 tree_view = owner.TreeView;
218 if (tree_view != null) {
219 tree_view.UpdateBelow (owner);
220 tree_view.RecalculateVisibleOrder (owner);
221 tree_view.UpdateScrollBars (false);
226 public bool Contains (TreeNode node)
228 return Array.IndexOf (nodes, node, 0, count) != -1;
231 public virtual bool ContainsKey (string key)
233 for (int i = 0; i < count; i++) {
234 if (string.Compare (nodes [i].Name, key, true, CultureInfo.InvariantCulture) == 0)
241 public void CopyTo (Array dest, int index)
243 Array.Copy (nodes, index, dest, index, count);
246 public IEnumerator GetEnumerator ()
248 return new TreeNodeEnumerator (this);
251 public int IndexOf (TreeNode node)
253 return Array.IndexOf (nodes, node);
257 public virtual int IndexOfKey (string key)
259 for (int i = 0; i < count; i++) {
260 if (string.Compare (nodes [i].Name, key, true, CultureInfo.InvariantCulture) == 0)
266 public virtual TreeNode Insert (int index, string text)
268 TreeNode node = new TreeNode (text);
269 Insert (index, node);
274 public virtual void Insert (int index, TreeNode node)
276 if (count >= nodes.Length)
279 Array.Copy (nodes, index, nodes, index + 1, count - index);
280 nodes [index] = node;
287 public virtual TreeNode Insert (int index, string key, string text)
289 TreeNode node = new TreeNode (text);
291 Insert (index, node);
295 public virtual TreeNode Insert (int index, string key, string text, int imageIndex)
297 TreeNode node = new TreeNode (text);
299 node.ImageIndex = imageIndex;
300 Insert (index, node);
304 public virtual TreeNode Insert (int index, string key, string text, string imageKey)
306 TreeNode node = new TreeNode (text);
308 node.ImageKey = imageKey;
309 Insert (index, node);
313 public virtual TreeNode Insert (int index, string key, string text, int imageIndex, int selectedImageIndex)
315 TreeNode node = new TreeNode (text, imageIndex, selectedImageIndex);
317 Insert (index, node);
321 public virtual TreeNode Insert (int index, string key, string text, string imageKey, string selectedImageKey)
323 TreeNode node = new TreeNode (text);
325 node.ImageKey = imageKey;
326 node.SelectedImageKey = selectedImageKey;
327 Insert (index, node);
332 public void Remove (TreeNode node)
335 throw new NullReferenceException ();
337 int index = IndexOf (node);
342 throw new NullReferenceException ();
346 public virtual void RemoveAt (int index)
348 RemoveAt (index, true);
351 private void RemoveAt (int index, bool update)
353 TreeNode removed = nodes [index];
354 TreeNode prev = GetPrevNode (removed);
355 TreeNode new_selected = null;
356 bool re_set_selected = false;
357 bool visible = removed.IsVisible;
359 TreeView tree_view = null;
361 tree_view = owner.TreeView;
363 if (tree_view != null) {
364 tree_view.RecalculateVisibleOrder (prev);
366 if (removed == tree_view.SelectedNode) {
367 re_set_selected = true;
368 OpenTreeNodeEnumerator oe = new OpenTreeNodeEnumerator (removed);
369 if (oe.MoveNext () && oe.MoveNext ()) {
370 new_selected = oe.CurrentNode;
372 oe = new OpenTreeNodeEnumerator (removed);
374 new_selected = oe.CurrentNode == removed ? null : oe.CurrentNode;
379 Array.Copy (nodes, index + 1, nodes, index, count - index - 1);
384 if (nodes.Length > OrigSize && nodes.Length > (count * 2))
387 if (tree_view != null && re_set_selected) {
388 tree_view.SelectedNode = new_selected;
391 TreeNode parent = removed.parent;
392 removed.parent = null;
394 if (update && tree_view != null && visible) {
395 tree_view.RecalculateVisibleOrder (prev);
396 tree_view.UpdateScrollBars (false);
397 tree_view.UpdateBelow (parent);
400 // UIA Framework Event: Collection Changed
401 if (tree_view != null)
402 tree_view.OnUIACollectionChanged (owner, new CollectionChangeEventArgs (CollectionChangeAction.Remove, removed));
407 public virtual void RemoveByKey (string key)
409 TreeNode node = this[key];
416 private TreeNode GetPrevNode (TreeNode node)
418 OpenTreeNodeEnumerator one = new OpenTreeNodeEnumerator (node);
420 if (one.MovePrevious () && one.MovePrevious ())
421 return one.CurrentNode;
425 private void SetupNode (TreeNode node)
427 // Remove it from any old parents
432 TreeView tree_view = null;
434 tree_view = owner.TreeView;
436 if (tree_view != null) {
438 if (tree_view.Sorted || tree_view.TreeViewNodeSorter != null) {
439 owner.Nodes.Sort (tree_view.TreeViewNodeSorter);
440 tree_view.sorted = sorted = true;
443 // We may need to invalidate this entire node collection if sorted.
444 TreeNode prev = sorted ? owner : GetPrevNode (node);
446 if (tree_view.IsHandleCreated && node.ArePreviousNodesExpanded)
447 tree_view.RecalculateVisibleOrder (prev);
448 if (owner == tree_view.root_node || node.Parent.IsVisible && node.Parent.IsExpanded)
449 tree_view.UpdateScrollBars (false);
452 if (owner != null && tree_view != null && (owner.IsExpanded || owner.IsRoot)) {
453 tree_view.UpdateBelow (owner);
454 } else if (owner != null && tree_view != null) {
455 tree_view.UpdateBelow (owner);
459 int IList.Add (object node)
461 return Add ((TreeNode) node);
464 bool IList.Contains (object node)
466 return Contains ((TreeNode) node);
469 int IList.IndexOf (object node)
471 return IndexOf ((TreeNode) node);
474 void IList.Insert (int index, object node)
476 Insert (index, (TreeNode) node);
479 void IList.Remove (object node)
481 Remove ((TreeNode) node);
484 private int AddSorted (TreeNode node)
486 if (count >= nodes.Length)
489 CompareInfo compare = Application.CurrentCulture.CompareInfo;
492 for (int i = 0; i < count; i++) {
494 int comp = compare.Compare (node.Text, nodes [i].Text);
501 // Stick it at the end
505 // Move the nodes up and adjust their indices
506 for (int i = count - 1; i >= pos; i--) {
507 nodes [i + 1] = nodes [i];
515 // Would be nice to do this without running through the collection twice
516 internal void Sort (IComparer sorter) {
517 Array.Sort (nodes, 0, count, sorter == null ? new TreeNodeComparer (Application.CurrentCulture.CompareInfo) : sorter);
519 for (int i = 0; i < count; i++) {
520 nodes [i].Nodes.Sort (sorter);
526 TreeNode [] nn = new TreeNode [nodes.Length + 50];
527 Array.Copy (nodes, nn, nodes.Length);
531 private void Shrink ()
533 int len = (count + 1 > OrigSize ? count + 1 : OrigSize);
534 TreeNode [] nn = new TreeNode [len];
535 Array.Copy (nodes, nn, count);
540 public TreeNode[] Find (string key, bool searchAllChildren)
542 List<TreeNode> results = new List<TreeNode> (0);
543 Find (key, searchAllChildren, this, results);
545 return results.ToArray ();
548 private static void Find (string key, bool searchAllChildren, TreeNodeCollection nodes, List<TreeNode> results)
550 for (int i = 0; i < nodes.Count; i++) {
551 TreeNode thisNode = nodes [i];
553 if (string.Compare (thisNode.Name, key, true, CultureInfo.InvariantCulture) == 0)
554 results.Add (thisNode);
557 // Need to match the Microsoft order.
559 if (searchAllChildren){
560 for (int i = 0; i < nodes.Count; i++){
561 TreeNodeCollection childNodes = nodes [i].Nodes;
562 if (childNodes.Count > 0) {
563 Find (key, searchAllChildren, childNodes, results);
569 internal class TreeNodeEnumerator : IEnumerator {
571 private TreeNodeCollection collection;
572 private int index = -1;
574 public TreeNodeEnumerator (TreeNodeCollection collection)
576 this.collection = collection;
579 public object Current {
583 return collection [index];
587 public bool MoveNext ()
589 if (index + 1 >= collection.Count)
601 private class TreeNodeComparer : IComparer {
603 private CompareInfo compare;
605 public TreeNodeComparer (CompareInfo compare)
607 this.compare = compare;
610 public int Compare (object x, object y)
612 TreeNode l = (TreeNode) x;
613 TreeNode r = (TreeNode) y;
614 int res = compare.Compare (l.Text, r.Text);
616 return (res == 0 ? l.Index - r.Index : res);