TreeNodeCollection.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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-2006 Novell, Inc.
  21. //
  22. // Authors:
  23. // Jackson Harper ([email protected])
  24. using System;
  25. using System.Collections;
  26. using System.ComponentModel;
  27. using System.Globalization;
  28. namespace System.Windows.Forms {
  29. [Editor("System.Windows.Forms.Design.TreeNodeCollectionEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
  30. public class TreeNodeCollection : IList, ICollection, IEnumerable {
  31. private static readonly int OrigSize = 50;
  32. private TreeNode owner;
  33. private int count;
  34. private TreeNode [] nodes;
  35. private TreeNodeCollection ()
  36. {
  37. }
  38. internal TreeNodeCollection (TreeNode owner)
  39. {
  40. this.owner = owner;
  41. nodes = new TreeNode [OrigSize];
  42. }
  43. [Browsable(false)]
  44. [EditorBrowsable(EditorBrowsableState.Advanced)]
  45. public int Count {
  46. get { return count; }
  47. }
  48. public bool IsReadOnly {
  49. get { return false; }
  50. }
  51. bool ICollection.IsSynchronized {
  52. get { return false; }
  53. }
  54. object ICollection.SyncRoot {
  55. get { return this; }
  56. }
  57. bool IList.IsFixedSize {
  58. get { return false; }
  59. }
  60. object IList.this [int index] {
  61. get {
  62. if (index < 0 || index >= Count)
  63. throw new ArgumentOutOfRangeException ("index");
  64. return nodes [index];
  65. }
  66. set {
  67. if (index < 0 || index >= Count)
  68. throw new ArgumentOutOfRangeException ("index");
  69. TreeNode node = (TreeNode) value;
  70. SetupNode (node);
  71. nodes [index] = node;
  72. }
  73. }
  74. public virtual TreeNode this [int index] {
  75. get {
  76. if (index < 0 || index >= Count)
  77. throw new ArgumentOutOfRangeException ("index");
  78. return nodes [index];
  79. }
  80. set {
  81. if (index < 0 || index >= Count)
  82. throw new ArgumentOutOfRangeException ("index");
  83. SetupNode (value);
  84. nodes [index] = value;
  85. }
  86. }
  87. public virtual TreeNode Add (string text)
  88. {
  89. TreeNode res = new TreeNode (text);
  90. Add (res);
  91. return res;
  92. }
  93. public virtual int Add (TreeNode node)
  94. {
  95. if (node == null)
  96. throw new ArgumentNullException("node");
  97. int res;
  98. TreeView tree_view = null;
  99. if (tree_view != null && tree_view.Sorted) {
  100. res = AddSorted (node);
  101. } else {
  102. if (count >= nodes.Length)
  103. Grow ();
  104. nodes [count++] = node;
  105. res = count;
  106. }
  107. SetupNode (node);
  108. return res;
  109. }
  110. public virtual void AddRange (TreeNode [] nodes)
  111. {
  112. if (nodes == null)
  113. throw new ArgumentNullException("node");
  114. // We can't just use Array.Copy because the nodes also
  115. // need to have some properties set when they are added.
  116. for (int i = 0; i < nodes.Length; i++)
  117. Add (nodes [i]);
  118. }
  119. public virtual void Clear ()
  120. {
  121. while (count > 0)
  122. RemoveAt (0, false);
  123. Array.Clear (nodes, 0, count);
  124. count = 0;
  125. TreeView tree_view = null;
  126. if (owner != null) {
  127. tree_view = owner.TreeView;
  128. if (owner.IsRoot)
  129. tree_view.top_node = null;
  130. if (tree_view != null) {
  131. tree_view.UpdateBelow (owner);
  132. tree_view.RecalculateVisibleOrder (owner);
  133. }
  134. }
  135. }
  136. public bool Contains (TreeNode node)
  137. {
  138. return (Array.BinarySearch (nodes, node) > 0);
  139. }
  140. public void CopyTo (Array dest, int index)
  141. {
  142. Array.Copy (nodes, index, dest, index, count);
  143. }
  144. public IEnumerator GetEnumerator ()
  145. {
  146. return new TreeNodeEnumerator (this);
  147. }
  148. public int IndexOf (TreeNode node)
  149. {
  150. return Array.IndexOf (nodes, node);
  151. }
  152. public virtual void Insert (int index, TreeNode node)
  153. {
  154. if (count >= nodes.Length)
  155. Grow ();
  156. Array.Copy (nodes, index, nodes, index + 1, count - index);
  157. nodes [index] = node;
  158. count++;
  159. SetupNode (node);
  160. }
  161. public void Remove (TreeNode node)
  162. {
  163. if (node == null)
  164. throw new NullReferenceException ();
  165. int index = IndexOf (node);
  166. if (index != -1)
  167. RemoveAt (index);
  168. #if ONLY_1_1
  169. else
  170. throw new NullReferenceException ();
  171. #endif
  172. }
  173. public virtual void RemoveAt (int index)
  174. {
  175. RemoveAt (index, true);
  176. }
  177. private void RemoveAt (int index, bool update)
  178. {
  179. TreeNode removed = nodes [index];
  180. TreeNode prev = GetPrevNode (removed);
  181. TreeNode new_selected = null;
  182. bool visible = removed.IsVisible;
  183. TreeView tree_view = null;
  184. if (owner != null)
  185. tree_view = owner.TreeView;
  186. if (tree_view != null) {
  187. tree_view.RecalculateVisibleOrder (prev);
  188. if (removed == tree_view.top_node) {
  189. if (removed.IsRoot) {
  190. tree_view.top_node = null;
  191. } else {
  192. OpenTreeNodeEnumerator oe = new OpenTreeNodeEnumerator (removed);
  193. if (oe.MovePrevious () && oe.MovePrevious ()) {
  194. tree_view.top_node = oe.CurrentNode;
  195. } else {
  196. removed.is_expanded = false;
  197. oe = new OpenTreeNodeEnumerator (removed);
  198. if (oe.MoveNext () && oe.MoveNext ()) {
  199. tree_view.top_node = oe.CurrentNode;
  200. } else {
  201. tree_view.top_node = null;
  202. }
  203. }
  204. }
  205. }
  206. if (removed == tree_view.selected_node) {
  207. OpenTreeNodeEnumerator oe = new OpenTreeNodeEnumerator (removed);
  208. if (oe.MoveNext () && oe.MoveNext ()) {
  209. new_selected = oe.CurrentNode;
  210. } else {
  211. oe = new OpenTreeNodeEnumerator (removed);
  212. oe.MovePrevious ();
  213. new_selected = oe.CurrentNode;
  214. }
  215. }
  216. }
  217. Array.Copy (nodes, index + 1, nodes, index, count - index);
  218. count--;
  219. if (nodes.Length > OrigSize && nodes.Length > (count * 2))
  220. Shrink ();
  221. if (tree_view != null && new_selected != null) {
  222. tree_view.SelectedNode = new_selected;
  223. }
  224. TreeNode parent = removed.parent;
  225. removed.parent = null;
  226. if (update && tree_view != null && visible) {
  227. tree_view.RecalculateVisibleOrder (prev);
  228. tree_view.UpdateScrollBars ();
  229. tree_view.UpdateBelow (parent);
  230. }
  231. }
  232. private TreeNode GetPrevNode (TreeNode node)
  233. {
  234. OpenTreeNodeEnumerator one = new OpenTreeNodeEnumerator (node);
  235. if (one.MovePrevious () && one.MovePrevious ())
  236. return one.CurrentNode;
  237. return null;
  238. }
  239. private void SetupNode (TreeNode node)
  240. {
  241. // Remove it from any old parents
  242. node.Remove ();
  243. node.parent = owner;
  244. TreeView tree_view = null;
  245. if (owner != null)
  246. tree_view = owner.TreeView;
  247. if (tree_view != null) {
  248. TreeNode prev = GetPrevNode (node);
  249. if (tree_view.top_node == null)
  250. tree_view.top_node = node;
  251. if (node.IsVisible)
  252. tree_view.RecalculateVisibleOrder (prev);
  253. if (owner == tree_view.root_node || node.Parent.IsVisible && node.Parent.IsExpanded)
  254. tree_view.UpdateScrollBars ();
  255. }
  256. if (owner != null && tree_view != null && (owner.IsExpanded || owner.IsRoot)) {
  257. // tree_view.UpdateBelow (owner);
  258. tree_view.UpdateNode (owner);
  259. tree_view.UpdateNode (node);
  260. } else if (owner != null && tree_view != null) {
  261. tree_view.UpdateBelow (owner);
  262. }
  263. }
  264. int IList.Add (object node)
  265. {
  266. return Add ((TreeNode) node);
  267. }
  268. bool IList.Contains (object node)
  269. {
  270. return Contains ((TreeNode) node);
  271. }
  272. int IList.IndexOf (object node)
  273. {
  274. return IndexOf ((TreeNode) node);
  275. }
  276. void IList.Insert (int index, object node)
  277. {
  278. Insert (index, (TreeNode) node);
  279. }
  280. void IList.Remove (object node)
  281. {
  282. Remove ((TreeNode) node);
  283. }
  284. private int AddSorted (TreeNode node)
  285. {
  286. if (count >= nodes.Length)
  287. Grow ();
  288. CompareInfo compare = Application.CurrentCulture.CompareInfo;
  289. int pos = 0;
  290. bool found = false;
  291. for (int i = 0; i < count; i++) {
  292. pos = i;
  293. int comp = compare.Compare (node.Text, nodes [i].Text);
  294. if (comp < 0) {
  295. found = true;
  296. break;
  297. }
  298. }
  299. // Stick it at the end
  300. if (!found)
  301. pos = count;
  302. // Move the nodes up and adjust their indices
  303. for (int i = count - 1; i >= pos; i--) {
  304. nodes [i + 1] = nodes [i];
  305. }
  306. count++;
  307. nodes [pos] = node;
  308. return count;
  309. }
  310. // Would be nice to do this without running through the collection twice
  311. internal void Sort () {
  312. Array.Sort (nodes, 0, count, new TreeNodeComparer (Application.CurrentCulture.CompareInfo));
  313. for (int i = 0; i < count; i++) {
  314. nodes [i].Nodes.Sort ();
  315. }
  316. }
  317. private void Grow ()
  318. {
  319. TreeNode [] nn = new TreeNode [nodes.Length + 50];
  320. Array.Copy (nodes, nn, nodes.Length);
  321. nodes = nn;
  322. }
  323. private void Shrink ()
  324. {
  325. int len = (count + 1 > OrigSize ? count + 1 : OrigSize);
  326. TreeNode [] nn = new TreeNode [len];
  327. Array.Copy (nodes, nn, count);
  328. nodes = nn;
  329. }
  330. internal class TreeNodeEnumerator : IEnumerator {
  331. private TreeNodeCollection collection;
  332. private int index = -1;
  333. public TreeNodeEnumerator (TreeNodeCollection collection)
  334. {
  335. this.collection = collection;
  336. }
  337. public object Current {
  338. get {
  339. if (index == -1)
  340. return null;
  341. return collection [index];
  342. }
  343. }
  344. public bool MoveNext ()
  345. {
  346. if (index + 1 >= collection.Count)
  347. return false;
  348. index++;
  349. return true;
  350. }
  351. public void Reset ()
  352. {
  353. index = -1;
  354. }
  355. }
  356. private class TreeNodeComparer : IComparer {
  357. private CompareInfo compare;
  358. public TreeNodeComparer (CompareInfo compare)
  359. {
  360. this.compare = compare;
  361. }
  362. public int Compare (object x, object y)
  363. {
  364. TreeNode l = (TreeNode) x;
  365. TreeNode r = (TreeNode) y;
  366. int res = compare.Compare (l.Text, r.Text);
  367. return (res == 0 ? l.Index - r.Index : res);
  368. }
  369. }
  370. }
  371. }