TreeNode.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  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 ([email protected])
  24. using System;
  25. using System.Text;
  26. using System.Drawing;
  27. using System.Runtime.Serialization;
  28. namespace System.Windows.Forms {
  29. [Serializable]
  30. public class TreeNode : MarshalByRefObject, ICloneable /*, ISerializable */ {
  31. private TreeView tree_view;
  32. internal TreeNode parent;
  33. private int index;
  34. private string text;
  35. private int image_index = -1;
  36. private int selected_image_index = -1;
  37. internal TreeNodeCollection nodes;
  38. private bool is_expanded = true;
  39. private Rectangle bounds = Rectangle.Empty;
  40. internal Rectangle plus_minus_bounds = Rectangle.Empty;
  41. private bool check;
  42. internal OwnerDrawPropertyBag prop_bag;
  43. private object tag;
  44. private IntPtr handle;
  45. internal TreeNode (TreeView tree_view) : this ()
  46. {
  47. this.tree_view = tree_view;
  48. }
  49. public TreeNode ()
  50. {
  51. nodes = new TreeNodeCollection (this);
  52. }
  53. public TreeNode (string text) : this ()
  54. {
  55. Text = text;
  56. }
  57. public TreeNode (string text, TreeNode [] children) : this (text)
  58. {
  59. Nodes.AddRange (children);
  60. }
  61. public TreeNode (string text, int image_index, int selected_image_index) : this (text)
  62. {
  63. this.image_index = image_index;
  64. this.selected_image_index = selected_image_index;
  65. }
  66. public TreeNode (string text, int image_index, int selected_image_index,
  67. TreeNode [] children) : this (text, image_index, selected_image_index)
  68. {
  69. Nodes.AddRange (children);
  70. }
  71. internal TreeView TreeView {
  72. get {
  73. if (tree_view != null)
  74. return tree_view;
  75. TreeNode walk = parent;
  76. while (walk != null) {
  77. if (walk.TreeView != null)
  78. tree_view = walk.TreeView;
  79. walk = walk.parent;
  80. }
  81. return tree_view;
  82. }
  83. }
  84. #region ICloneable Members
  85. public object Clone()
  86. {
  87. TreeNode tn = new TreeNode (text, image_index, selected_image_index);
  88. if (nodes != null) {
  89. foreach (TreeNode child in nodes)
  90. tn.Nodes.Add ((TreeNode)child.Clone ());
  91. }
  92. tn.Tag = tag;
  93. tn.Checked = Checked;
  94. if (prop_bag != null)
  95. tn.prop_bag = OwnerDrawPropertyBag.Copy (prop_bag);
  96. return tn;
  97. }
  98. #endregion
  99. public TreeNode Parent {
  100. get {
  101. if (tree_view != null && tree_view.root_node == parent)
  102. return null;
  103. return parent;
  104. }
  105. }
  106. public string Text {
  107. get {
  108. if (text == null)
  109. return String.Empty;
  110. return text;
  111. }
  112. set {
  113. if (text == value)
  114. return;
  115. text = value;
  116. bounds.Width = 0;
  117. }
  118. }
  119. public Rectangle Bounds {
  120. get { return bounds; }
  121. }
  122. internal Rectangle PlusMinusBounds {
  123. get { return plus_minus_bounds; }
  124. }
  125. public bool Checked {
  126. get { return check; }
  127. set { check = value; }
  128. }
  129. public Color BackColor {
  130. get {
  131. return prop_bag == null ? Color.Empty : prop_bag.BackColor;
  132. }
  133. set {
  134. if (prop_bag == null)
  135. prop_bag = new OwnerDrawPropertyBag ();
  136. prop_bag.BackColor = value;
  137. }
  138. }
  139. public Color ForeColor {
  140. get {
  141. return prop_bag == null ? Color.Empty : prop_bag.ForeColor;
  142. }
  143. set {
  144. if (prop_bag == null)
  145. prop_bag = new OwnerDrawPropertyBag ();
  146. prop_bag.ForeColor = value;
  147. }
  148. }
  149. public Font NodeFont {
  150. get {
  151. return prop_bag == null ? null : prop_bag.Font;
  152. }
  153. set {
  154. if (prop_bag == null)
  155. prop_bag = new OwnerDrawPropertyBag ();
  156. prop_bag.Font = value;
  157. }
  158. }
  159. public TreeNodeCollection Nodes {
  160. get {
  161. if (nodes == null)
  162. nodes = new TreeNodeCollection (this);
  163. return nodes;
  164. }
  165. }
  166. public TreeNode FirstNode {
  167. get {
  168. if (nodes.Count > 0)
  169. return nodes [0];
  170. return null;
  171. }
  172. }
  173. public string FullPath {
  174. get {
  175. if (tree_view == null)
  176. throw new Exception ("No TreeView associated");
  177. StringBuilder builder = new StringBuilder ();
  178. BuildFullPath (builder);
  179. return builder.ToString ();
  180. }
  181. }
  182. bool BuildFullPath (StringBuilder path)
  183. {
  184. if (parent == null)
  185. return false;
  186. if (parent.BuildFullPath (path))
  187. path.Append (tree_view.PathSeparator);
  188. path.Append (text);
  189. return true;
  190. }
  191. public bool IsExpanded {
  192. get { return is_expanded; }
  193. }
  194. public TreeNode NextNode {
  195. get {
  196. if (parent == null)
  197. return null;
  198. if (parent.Nodes.Count > index + 1)
  199. return parent.Nodes [index + 1];
  200. return null;
  201. }
  202. }
  203. public TreeNode PrevNode {
  204. get {
  205. if (parent == null)
  206. return null;
  207. if (index == 0 || index > parent.Nodes.Count)
  208. return null;
  209. return parent.Nodes [index - 1];
  210. }
  211. }
  212. public TreeNode NextVisibleNode {
  213. get {
  214. OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
  215. if (!o.MoveNext ())
  216. return null;
  217. TreeNode c = (TreeNode) o.Current;
  218. if (!c.IsInClippingRect)
  219. return null;
  220. return c;
  221. }
  222. }
  223. public TreeNode PrevVisibleNode {
  224. get {
  225. OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
  226. if (!o.MovePrevious ())
  227. return null;
  228. TreeNode c = (TreeNode) o.Current;
  229. if (!c.IsInClippingRect)
  230. return null;
  231. return c;
  232. }
  233. }
  234. public TreeNode LastNode {
  235. get {
  236. return (nodes == null || nodes.Count == 0) ? null : nodes [nodes.Count - 1];
  237. }
  238. }
  239. public int Index {
  240. get { return index; }
  241. }
  242. public int ImageIndex {
  243. get { return image_index; }
  244. set { image_index = value; }
  245. }
  246. public int SelectedImageIndex {
  247. get { return selected_image_index; }
  248. set { selected_image_index = value; }
  249. }
  250. public object Tag {
  251. get { return tag; }
  252. set { tag = value; }
  253. }
  254. public void Expand ()
  255. {
  256. if (is_expanded)
  257. return;
  258. bool cancel = false;
  259. if (TreeView != null) {
  260. TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Expand);
  261. TreeView.OnBeforeCollapse (e);
  262. cancel = e.Cancel;
  263. }
  264. if (!cancel) {
  265. is_expanded = true;
  266. if (TreeView != null)
  267. TreeView.OnAfterCollapse (new TreeViewEventArgs (this));
  268. if (IsNodeVisible () && TreeView != null)
  269. TreeView.UpdateBelow (this);
  270. }
  271. }
  272. public void Collapse ()
  273. {
  274. if (!is_expanded)
  275. return;
  276. bool cancel = false;
  277. if (TreeView != null) {
  278. TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Collapse);
  279. TreeView.OnBeforeCollapse (e);
  280. cancel = e.Cancel;
  281. }
  282. if (!cancel) {
  283. is_expanded = false;
  284. if (TreeView != null)
  285. TreeView.OnAfterCollapse (new TreeViewEventArgs (this));
  286. if (IsNodeVisible () && TreeView != null)
  287. TreeView.UpdateBelow (this);
  288. }
  289. }
  290. public void Remove ()
  291. {
  292. if (parent == null)
  293. return;
  294. parent.Nodes.RemoveAt (Index);
  295. }
  296. public void ExpandAll ()
  297. {
  298. ExpandRecursive (this);
  299. }
  300. private void ExpandRecursive (TreeNode node)
  301. {
  302. node.Expand ();
  303. foreach (TreeNode child in node.Nodes) {
  304. ExpandRecursive (child);
  305. }
  306. }
  307. internal void CollapseAll ()
  308. {
  309. CollapseRecursive (this);
  310. }
  311. private void CollapseRecursive (TreeNode node)
  312. {
  313. node.Collapse ();
  314. foreach (TreeNode child in node.Nodes) {
  315. CollapseRecursive (child);
  316. }
  317. }
  318. public int GetNodeCount (bool include_subtrees)
  319. {
  320. if (!include_subtrees)
  321. return Nodes.Count;
  322. int count = 0;
  323. GetNodeCountRecursive (this, ref count);
  324. return count;
  325. }
  326. public void Toggle ()
  327. {
  328. if (is_expanded)
  329. Collapse ();
  330. else
  331. Expand ();
  332. if (TreeView != null)
  333. TreeView.Refresh ();
  334. }
  335. internal void SetNodes (TreeNodeCollection nodes)
  336. {
  337. this.nodes = nodes;
  338. }
  339. private void GetNodeCountRecursive (TreeNode node, ref int count)
  340. {
  341. count += node.Nodes.Count;
  342. foreach (TreeNode child in node.Nodes) {
  343. GetNodeCountRecursive (child, ref count);
  344. }
  345. }
  346. public override String ToString ()
  347. {
  348. return String.Concat ("TreeNode: ", Text);
  349. }
  350. internal void UpdateBounds (int x, int y, int width, int height)
  351. {
  352. bounds.X = x;
  353. bounds.Y = y;
  354. bounds.Width = width;
  355. bounds.Height = height;
  356. }
  357. internal void UpdatePlusMinusBounds (int x, int y, int width, int height)
  358. {
  359. plus_minus_bounds.X = x;
  360. plus_minus_bounds.Y = y;
  361. plus_minus_bounds.Width = width;
  362. plus_minus_bounds.Height = height;
  363. }
  364. internal void SetAddedData (TreeView tree_view, TreeNode parent, int index)
  365. {
  366. this.tree_view = tree_view;
  367. this.parent = parent;
  368. this.index = index;
  369. }
  370. private bool IsInClippingRect
  371. {
  372. get {
  373. if (TreeView == null)
  374. return false;
  375. if (bounds.Y < 0 && bounds.Y > tree_view.ClientRectangle.Height)
  376. return false;
  377. return true;
  378. }
  379. }
  380. private bool IsNodeVisible ()
  381. {
  382. if (TreeView == null)
  383. return false;
  384. if (bounds.Y < 0 && bounds.Y > TreeView.ClientRectangle.Height)
  385. return false;
  386. TreeNode parent = Parent;
  387. while (parent != null) {
  388. if (!parent.IsExpanded)
  389. return false;
  390. parent = parent.Parent;
  391. }
  392. return true;
  393. }
  394. }
  395. }