* TreeView.cs: Refresh the tree after sorting the nodes. Always
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TreeNodeCollection.cs
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:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
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.
19 //
20 // Copyright (c) 2004 Novell, Inc.
21 //
22 // Authors:
23 //      Jackson Harper (jackson@ximian.com)
24
25 // TODO: Sorting
26
27 using System;
28 using System.Collections;
29 using System.Globalization;
30
31 namespace System.Windows.Forms {
32
33         public class TreeNodeCollection : IList, ICollection, IEnumerable {
34
35                 private static readonly int OrigSize = 50;
36
37                 private TreeNode owner;
38                 private int count;
39                 private TreeNode [] nodes;
40
41                 private TreeNodeCollection ()
42                 {
43                 }
44
45                 internal TreeNodeCollection (TreeNode owner)
46                 {
47                         this.owner = owner;
48                         nodes = new TreeNode [OrigSize];
49                 }
50
51                 public virtual int Count {
52                         get { return count; }
53                 }
54
55                 public virtual bool IsReadOnly {
56                         get { return false; }
57                 }
58
59                 bool ICollection.IsSynchronized {
60                         get { return false; }
61                 }
62
63                 object ICollection.SyncRoot {
64                         get { return this; }
65                 }
66
67                 bool IList.IsFixedSize {
68                         get { return false; }
69                 }
70
71                 object IList.this [int index] {
72                         get {
73                                 if (index < 0 || index > Count)
74                                         throw new ArgumentOutOfRangeException ("index");
75                                 return nodes [index];
76                         }
77                         set {
78                                 if (index < 0 || index > Count)
79                                         throw new ArgumentOutOfRangeException ("index");
80                                 TreeNode node = (TreeNode) value;
81                                 SetData (node);
82                                 nodes [index] = node;
83                         }
84                 }
85
86                 public virtual TreeNode this [int index] {
87                         get {
88                                 if (index < 0 || index > Count)
89                                         throw new ArgumentOutOfRangeException ("index");
90                                 return nodes [index];
91                         }
92                         set {
93                                 if (index < 0 || index > Count)
94                                         throw new ArgumentOutOfRangeException ("index");
95                                 SetData (value);
96                                 nodes [index] = value;
97                         }
98                 }
99
100                 public virtual TreeNode Add (string text)
101                 {
102                         TreeNode res = new TreeNode (text);
103                         Add (res);
104                         return res;
105                 }
106
107                 public virtual int Add (TreeNode node)
108                 {
109                         if (node == null)
110                                 throw new ArgumentNullException("node");
111
112                         if (owner != null && owner.TreeView != null && owner.TreeView.Sorted)
113                                 return AddSorted (node);
114                         SetData (node);
115                         if (count >= nodes.Length)
116                                 Grow ();
117                         nodes [count++] = node;
118
119                         if (owner.TreeView != null)
120                                 owner.TreeView.Refresh ();
121                         return count;
122                 }
123
124                 public virtual void AddRange (TreeNode [] nodes)
125                 {
126                         if (nodes == null)
127                                 throw new ArgumentNullException("node");
128
129                         // We can't just use Array.Copy because the nodes also
130                         // need to have some properties set when they are added.
131                         for (int i = 0; i < nodes.Length; i++)
132                                 Add (nodes [i]);
133                 }
134
135                 public virtual void Clear ()
136                 {
137                         Array.Clear (nodes, 0, count);
138                         count = 0;
139                 }
140
141                 public bool Contains (TreeNode node)
142                 {
143                         return (Array.BinarySearch (nodes, node) > 0);
144                 }
145
146                 public virtual void CopyTo (Array dest, int index)
147                 {
148                         nodes.CopyTo (dest, index);
149                 }
150
151                 public virtual IEnumerator GetEnumerator ()
152                 {
153                         return new TreeNodeEnumerator (this);
154                 }
155
156                 public int IndexOf (TreeNode node)
157                 {
158                         return Array.IndexOf (nodes, node);
159                 }
160
161                 public virtual void Insert (int index, TreeNode node)
162                 {
163                         SetData (node);
164                         IList list = (IList) nodes;
165                         list.Insert (index, node);
166                 }
167
168                 public virtual void Remove (TreeNode node)
169                 {
170                         int index = IndexOf (node);
171                         if (index > 0)
172                                 RemoveAt (index);
173                 }
174
175                 public virtual void RemoveAt (int index)
176                 {
177                         Array.Copy (nodes, index, nodes, index - 1, count - index);
178                         count--;
179                         if (nodes.Length > OrigSize && nodes.Length > (count * 2))
180                                 Shrink ();
181                         if (owner.TreeView != null)
182                                 owner.TreeView.TotalNodeCount--;
183                 }
184
185                 int IList.Add (object node)
186                 {
187                         return Add ((TreeNode) node);
188                 }
189
190                 bool IList.Contains (object node)
191                 {
192                         return Contains ((TreeNode) node);
193                 }
194                 
195                 int IList.IndexOf (object node)
196                 {
197                         return IndexOf ((TreeNode) node);
198                 }
199
200                 void IList.Insert (int index, object node)
201                 {
202                         Insert (index, (TreeNode) node);
203                 }
204
205                 void IList.Remove (object node)
206                 {
207                         Remove ((TreeNode) node);
208                 }
209
210                 private int AddSorted (TreeNode node)
211                 {
212                         
213                         if (count >= nodes.Length)
214                                 Grow ();
215
216                         CompareInfo compare = Application.CurrentCulture.CompareInfo;
217                         int pos = 0;
218                         bool found = false;
219                         for (int i = 0; i < count; i++) {
220                                 pos = i;
221                                 int comp = compare.Compare (node.Text, nodes [i].Text);
222                                 if (comp < 0) {
223                                         found = true;
224                                         break;
225                                 }
226                         }
227
228                         // Stick it at the end
229                         if (!found)
230                                 pos = count;
231
232                         // Move the nodes up and adjust their indices
233                         for (int i = count - 1; i >= pos; i--) {
234                                 nodes [i + 1] = nodes [i];
235                                 nodes [i + 1].SetIndex (i + 1);
236                         }
237                         count++;
238                         nodes [pos] = node;
239
240                         SetData (node, pos);
241                         return count;
242                 }
243
244                 // Would be nice to do this without running through the collection twice
245                 internal void Sort () {
246
247                         Array.Sort (nodes, 0, count, new TreeNodeComparer (Application.CurrentCulture.CompareInfo));
248
249                         for (int i = 0; i < count; i++) {
250                                 nodes [i].SetIndex (i);
251                                 nodes [i].Nodes.Sort ();
252                         }
253                 }
254
255                 private void SetData (TreeNode node)
256                 {
257                         SetData (node, count);
258                 }
259
260                 private void SetData (TreeNode node, int pos)
261                 {
262                         node.SetAddedData ((owner != null ? owner.TreeView : null), owner, pos);
263                 }
264
265                 private void Grow ()
266                 {
267                         TreeNode [] nn = new TreeNode [nodes.Length + 50];
268                         Array.Copy (nodes, nn, nodes.Length);
269                         nodes = nn;
270                 }
271
272                 private void Shrink ()
273                 {
274                         int len = (count > OrigSize ? count : OrigSize);
275                         TreeNode [] nn = new TreeNode [len];
276                         Array.Copy (nodes, nn, count);
277                         nodes = nn;
278                 }
279
280                 
281                 internal class TreeNodeEnumerator : IEnumerator {
282
283                         private TreeNodeCollection collection;
284                         private int index = -1;
285
286                         public TreeNodeEnumerator (TreeNodeCollection collection)
287                         {
288                                 this.collection = collection;
289                         }
290
291                         public object Current {
292                                 get { return collection [index]; }
293                         }
294
295                         public bool MoveNext ()
296                         {
297                                 if (index + 1 >= collection.Count)
298                                         return false;
299                                 index++;
300                                 return true;
301                         }
302
303                         public void Reset ()
304                         {
305                                 index = 0;
306                         }
307                 }
308
309                 private class TreeNodeComparer : IComparer {
310
311                         private CompareInfo compare;
312                 
313                         public TreeNodeComparer (CompareInfo compare)
314                         {
315                                 this.compare = compare;
316                         }
317                 
318                         public int Compare (object x, object y)
319                         {
320                                 TreeNode l = (TreeNode) x;
321                                 TreeNode r = (TreeNode) y;
322                                 int res = compare.Compare (l.Text, r.Text);
323
324                                 return (res == 0 ? l.Index - r.Index : res);
325                         }
326                 }
327         }
328 }
329