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
;
31 namespace System
.Windows
.Forms
{
32 [Editor("System.Windows.Forms.Design.TreeNodeCollectionEditor, " + Consts
.AssemblySystem_Design
, typeof(System
.Drawing
.Design
.UITypeEditor
))]
33 public class TreeNodeCollection
: IList
, ICollection
, IEnumerable
{
35 private static readonly int OrigSize
= 50;
37 private TreeNode owner
;
39 private TreeNode
[] nodes
;
41 private TreeNodeCollection ()
45 internal TreeNodeCollection (TreeNode owner
)
48 nodes
= new TreeNode
[OrigSize
];
52 [EditorBrowsable(EditorBrowsableState
.Advanced
)]
57 public bool IsReadOnly
{
61 bool ICollection
.IsSynchronized
{
65 object ICollection
.SyncRoot
{
69 bool IList
.IsFixedSize
{
73 object IList
.this [int index
] {
78 if (!(value is TreeNode
))
79 throw new ArgumentException ("value");
80 this [index
] = (TreeNode
) value;
84 public virtual TreeNode
this [int index
] {
86 if (index
< 0 || index
>= Count
)
87 throw new ArgumentOutOfRangeException ("index");
91 if (index
< 0 || index
>= Count
)
92 throw new ArgumentOutOfRangeException ("index");
94 nodes
[index
] = value;
98 public virtual TreeNode
Add (string text
)
100 TreeNode res
= new TreeNode (text
);
105 public virtual int Add (TreeNode node
)
108 throw new ArgumentNullException("node");
111 TreeView tree_view
= null;
113 if (tree_view
!= null && tree_view
.Sorted
) {
114 res
= AddSorted (node
);
116 if (count
>= nodes
.Length
)
118 nodes
[count
++] = node
;
127 public virtual void AddRange (TreeNode
[] nodes
)
130 throw new ArgumentNullException("node");
132 // We can't just use Array.Copy because the nodes also
133 // need to have some properties set when they are added.
134 for (int i
= 0; i
< nodes
.Length
; i
++)
138 public virtual void Clear ()
143 Array
.Clear (nodes
, 0, count
);
146 TreeView tree_view
= null;
148 tree_view
= owner
.TreeView
;
150 tree_view
.top_node
= null;
151 if (tree_view
!= null) {
152 tree_view
.UpdateBelow (owner
);
153 tree_view
.RecalculateVisibleOrder (owner
);
154 tree_view
.UpdateScrollBars ();
159 public bool Contains (TreeNode node
)
161 return (Array
.BinarySearch (nodes
, node
) > 0);
164 public void CopyTo (Array dest
, int index
)
166 Array
.Copy (nodes
, index
, dest
, index
, count
);
169 public IEnumerator
GetEnumerator ()
171 return new TreeNodeEnumerator (this);
174 public int IndexOf (TreeNode node
)
176 return Array
.IndexOf (nodes
, node
);
179 public virtual void Insert (int index
, TreeNode node
)
181 if (count
>= nodes
.Length
)
184 Array
.Copy (nodes
, index
, nodes
, index
+ 1, count
- index
);
185 nodes
[index
] = node
;
191 public void Remove (TreeNode node
)
194 throw new NullReferenceException ();
196 int index
= IndexOf (node
);
201 throw new NullReferenceException ();
205 public virtual void RemoveAt (int index
)
207 RemoveAt (index
, true);
210 private void RemoveAt (int index
, bool update
)
212 TreeNode removed
= nodes
[index
];
213 TreeNode prev
= GetPrevNode (removed
);
214 TreeNode new_selected
= null;
215 bool visible
= removed
.IsVisible
;
217 TreeView tree_view
= null;
219 tree_view
= owner
.TreeView
;
221 if (tree_view
!= null) {
222 tree_view
.RecalculateVisibleOrder (prev
);
223 if (removed
== tree_view
.top_node
) {
225 if (removed
.IsRoot
) {
226 tree_view
.top_node
= null;
228 OpenTreeNodeEnumerator oe
= new OpenTreeNodeEnumerator (removed
);
229 if (oe
.MovePrevious () && oe
.MovePrevious ()) {
230 tree_view
.top_node
= oe
.CurrentNode
;
232 removed
.is_expanded
= false;
233 oe
= new OpenTreeNodeEnumerator (removed
);
234 if (oe
.MoveNext () && oe
.MoveNext ()) {
235 tree_view
.top_node
= oe
.CurrentNode
;
237 tree_view
.top_node
= null;
242 if (removed
== tree_view
.selected_node
) {
243 OpenTreeNodeEnumerator oe
= new OpenTreeNodeEnumerator (removed
);
244 if (oe
.MoveNext () && oe
.MoveNext ()) {
245 new_selected
= oe
.CurrentNode
;
247 oe
= new OpenTreeNodeEnumerator (removed
);
249 new_selected
= oe
.CurrentNode
;
254 Array
.Copy (nodes
, index
+ 1, nodes
, index
, count
- index
);
256 if (nodes
.Length
> OrigSize
&& nodes
.Length
> (count
* 2))
259 if (tree_view
!= null && new_selected
!= null) {
260 tree_view
.SelectedNode
= new_selected
;
263 TreeNode parent
= removed
.parent
;
264 removed
.parent
= null;
266 if (update
&& tree_view
!= null && visible
) {
267 tree_view
.RecalculateVisibleOrder (prev
);
268 tree_view
.UpdateScrollBars ();
269 tree_view
.UpdateBelow (parent
);
273 private TreeNode
GetPrevNode (TreeNode node
)
275 OpenTreeNodeEnumerator one
= new OpenTreeNodeEnumerator (node
);
277 if (one
.MovePrevious () && one
.MovePrevious ())
278 return one
.CurrentNode
;
282 private void SetupNode (TreeNode node
)
284 // Remove it from any old parents
289 TreeView tree_view
= null;
291 tree_view
= owner
.TreeView
;
293 if (tree_view
!= null) {
294 TreeNode prev
= GetPrevNode (node
);
296 if (tree_view
.top_node
== null)
297 tree_view
.top_node
= node
;
300 tree_view
.RecalculateVisibleOrder (prev
);
301 if (owner
== tree_view
.root_node
|| node
.Parent
.IsVisible
&& node
.Parent
.IsExpanded
)
302 tree_view
.UpdateScrollBars ();
305 if (owner
!= null && tree_view
!= null && (owner
.IsExpanded
|| owner
.IsRoot
)) {
306 // tree_view.UpdateBelow (owner);
307 tree_view
.UpdateNode (owner
);
308 tree_view
.UpdateNode (node
);
309 } else if (owner
!= null && tree_view
!= null) {
310 tree_view
.UpdateBelow (owner
);
314 int IList
.Add (object node
)
316 return Add ((TreeNode
) node
);
319 bool IList
.Contains (object node
)
321 return Contains ((TreeNode
) node
);
324 int IList
.IndexOf (object node
)
326 return IndexOf ((TreeNode
) node
);
329 void IList
.Insert (int index
, object node
)
331 Insert (index
, (TreeNode
) node
);
334 void IList
.Remove (object node
)
336 Remove ((TreeNode
) node
);
339 private int AddSorted (TreeNode node
)
341 if (count
>= nodes
.Length
)
344 CompareInfo compare
= Application
.CurrentCulture
.CompareInfo
;
347 for (int i
= 0; i
< count
; i
++) {
349 int comp
= compare
.Compare (node
.Text
, nodes
[i
].Text
);
356 // Stick it at the end
360 // Move the nodes up and adjust their indices
361 for (int i
= count
- 1; i
>= pos
; i
--) {
362 nodes
[i
+ 1] = nodes
[i
];
370 // Would be nice to do this without running through the collection twice
371 internal void Sort () {
372 Array
.Sort (nodes
, 0, count
, new TreeNodeComparer (Application
.CurrentCulture
.CompareInfo
));
374 for (int i
= 0; i
< count
; i
++) {
375 nodes
[i
].Nodes
.Sort ();
381 TreeNode
[] nn
= new TreeNode
[nodes
.Length
+ 50];
382 Array
.Copy (nodes
, nn
, nodes
.Length
);
386 private void Shrink ()
388 int len
= (count
+ 1 > OrigSize
? count
+ 1 : OrigSize
);
389 TreeNode
[] nn
= new TreeNode
[len
];
390 Array
.Copy (nodes
, nn
, count
);
395 internal class TreeNodeEnumerator
: IEnumerator
{
397 private TreeNodeCollection collection
;
398 private int index
= -1;
400 public TreeNodeEnumerator (TreeNodeCollection collection
)
402 this.collection
= collection
;
405 public object Current
{
409 return collection
[index
];
413 public bool MoveNext ()
415 if (index
+ 1 >= collection
.Count
)
427 private class TreeNodeComparer
: IComparer
{
429 private CompareInfo compare
;
431 public TreeNodeComparer (CompareInfo compare
)
433 this.compare
= compare
;
436 public int Compare (object x
, object y
)
438 TreeNode l
= (TreeNode
) x
;
439 TreeNode r
= (TreeNode
) y
;
440 int res
= compare
.Compare (l
.Text
, r
.Text
);
442 return (res
== 0 ? l
.Index
- r
.Index
: res
);