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-2005 Novell, Inc.
23 // Jackson Harper (jackson@ximian.com)
24 // Kazuki Oikawa (kazuki@panicode.com)
27 using System.ComponentModel;
29 using System.Runtime.Serialization;
32 namespace System.Windows.Forms {
33 [TypeConverter(typeof(TreeNodeConverter))]
35 public class TreeNode : MarshalByRefObject, ICloneable, ISerializable {
37 private TreeView tree_view;
38 internal TreeNode parent;
42 private int image_index = -1;
43 private int selected_image_index = -1;
44 internal TreeNodeCollection nodes;
46 private bool is_expanded = false;
47 private Rectangle bounds = Rectangle.Empty;
49 private bool is_editing;
50 internal OwnerDrawPropertyBag prop_bag;
54 internal IntPtr handle;
58 #region Internal Constructors
59 internal TreeNode (TreeView tree_view) : this ()
61 this.tree_view = tree_view;
65 private TreeNode (SerializationInfo info, StreamingContext context) : this ()
67 Text = (string) info.GetValue ("Text", typeof (string));
68 prop_bag = (OwnerDrawPropertyBag) info.GetValue ("prop_bag", typeof (OwnerDrawPropertyBag));
69 image_index = (int) info.GetValue ("ImageIndex", typeof (int));
70 selected_image_index = (int) info.GetValue ("SelectedImageIndex", typeof (int));
71 tag = info.GetValue ("Tag", typeof (object));
72 check = (bool) info.GetValue ("Checked", typeof (bool));
74 int count = (int) info.GetValue ("NumberOfChildren", typeof (int));
75 for (int i = 0; i < count; i++) {
76 TreeNode node = (TreeNode) info.GetValue ("Child-" + i, typeof (TreeNode));
81 #endregion // Internal Constructors
83 #region Public Constructors
86 nodes = new TreeNodeCollection (this);
89 public TreeNode (string text) : this ()
94 public TreeNode (string text, TreeNode [] children) : this (text)
96 Nodes.AddRange (children);
99 public TreeNode (string text, int image_index, int selected_image_index) : this (text)
101 this.image_index = image_index;
102 this.selected_image_index = selected_image_index;
105 public TreeNode (string text, int image_index, int selected_image_index,
106 TreeNode [] children) : this (text, image_index, selected_image_index)
108 Nodes.AddRange (children);
111 #endregion // Public Constructors
113 #region ICloneable Members
114 public object Clone()
116 TreeNode tn = new TreeNode (text, image_index, selected_image_index);
118 foreach (TreeNode child in nodes)
119 tn.Nodes.Add ((TreeNode)child.Clone ());
122 tn.Checked = Checked;
123 if (prop_bag != null)
124 tn.prop_bag = OwnerDrawPropertyBag.Copy (prop_bag);
128 #endregion // ICloneable Members
130 #region ISerializable Members
131 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
133 info.AddValue ("Text", Text);
134 info.AddValue ("prop_bag", prop_bag, typeof (OwnerDrawPropertyBag));
135 info.AddValue ("ImageIndex", ImageIndex);
136 info.AddValue ("SelectedImageIndex", SelectedImageIndex);
137 info.AddValue ("Tag", Tag);
138 info.AddValue ("Checked", Checked);
140 info.AddValue ("NumberOfChildren", Nodes.Count);
141 for (int i = 0; i < Nodes.Count; i++)
142 info.AddValue ("Child-" + i, Nodes [i], typeof (TreeNode));
144 #endregion // ISerializable Members
146 #region Public Instance Properties
147 public Color BackColor {
149 if (prop_bag != null)
150 return prop_bag.BackColor;
151 if (TreeView != null)
152 return TreeView.BackColor;
156 if (prop_bag == null)
157 prop_bag = new OwnerDrawPropertyBag ();
158 prop_bag.BackColor = value;
162 public Rectangle Bounds {
163 get { return bounds; }
166 public bool Checked {
167 get { return check; }
173 if (TreeView != null)
174 TreeView.UpdateNode (this);
178 public TreeNode FirstNode {
186 public Color ForeColor {
188 if (prop_bag != null)
189 return prop_bag.ForeColor;
190 if (TreeView != null)
191 return TreeView.ForeColor;
195 if (prop_bag == null)
196 prop_bag = new OwnerDrawPropertyBag ();
197 prop_bag.ForeColor = value;
201 public string FullPath {
203 if (tree_view == null)
204 throw new Exception ("No TreeView associated");
206 StringBuilder builder = new StringBuilder ();
207 BuildFullPath (builder);
208 return builder.ToString ();
213 public int ImageIndex {
214 get { return image_index; }
215 set { image_index = value; }
218 public bool IsEditing {
219 get { return is_editing; }
222 public bool IsExpanded {
223 get { return is_expanded; }
226 public bool IsSelected {
228 if (TreeView == null)
230 return TreeView.SelectedNode == this;
234 public bool IsVisible {
236 if (TreeView == null)
239 if (bounds.Y < 0 && bounds.Y > TreeView.ClientRectangle.Height)
242 TreeNode parent = Parent;
243 while (parent != null) {
244 if (!parent.IsExpanded)
246 parent = parent.Parent;
252 public TreeNode LastNode {
254 return (nodes == null || nodes.Count == 0) ? null : nodes [nodes.Count - 1];
258 public TreeNode NextNode {
262 if (parent.Nodes.Count > index + 1)
263 return parent.Nodes [index + 1];
268 public TreeNode NextVisibleNode {
270 OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
273 TreeNode c = (TreeNode) o.Current;
274 if (!c.IsInClippingRect)
281 public Font NodeFont {
283 if (prop_bag != null)
284 return prop_bag.Font;
285 if (TreeView != null)
286 return TreeView.Font;
290 if (prop_bag == null)
291 prop_bag = new OwnerDrawPropertyBag ();
292 prop_bag.Font = value;
297 [ListBindable(false)]
298 public TreeNodeCollection Nodes {
301 nodes = new TreeNodeCollection (this);
306 public TreeNode Parent {
308 if (tree_view != null && tree_view.root_node == parent)
314 public TreeNode PrevNode {
318 if (index == 0 || index > parent.Nodes.Count)
320 return parent.Nodes [index - 1];
324 public TreeNode PrevVisibleNode {
326 OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
327 if (!o.MovePrevious ())
329 TreeNode c = (TreeNode) o.Current;
330 if (!c.IsInClippingRect)
337 public int SelectedImageIndex {
338 get { return selected_image_index; }
339 set { selected_image_index = value; }
344 [TypeConverter(typeof(System.ComponentModel.StringConverter))]
366 public TreeView TreeView {
368 if (tree_view != null)
370 TreeNode walk = parent;
371 while (walk != null) {
372 if (walk.TreeView != null)
373 tree_view = walk.TreeView;
380 public IntPtr Handle {
382 // MS throws a NullReferenceException if the TreeView isn't set...
383 if (handle == IntPtr.Zero)
384 handle = TreeView.CreateNodeHandle ();
389 #endregion // Public Instance Properties
392 public static TreeNode FromHandle (TreeView tree, IntPtr handle)
394 if (handle == IntPtr.Zero)
396 // No arg checking on MS it just throws a NullRef if treeview is null
397 return tree.NodeFromHandle (handle);
400 #region Public Instance Methods
401 public void BeginEdit () {
405 public void Collapse () {
409 public void EndEdit (bool cancel) {
411 if (!cancel && TreeView != null)
412 Text = TreeView.LabelEditText;
415 public void Expand () {
419 public void ExpandAll () {
420 ExpandRecursive (this);
422 TreeView.UpdateNode (TreeView.root_node);
425 public void EnsureVisible ()
427 if (TreeView == null)
430 if (this.Parent != null)
431 ExpandParentRecursive (this.Parent);
434 TreeView.SetTop (this);
435 } else if (bounds.Bottom > TreeView.ViewportRectangle.Bottom) {
436 TreeView.SetBottom (this);
440 public int GetNodeCount (bool include_subtrees) {
441 if (!include_subtrees)
445 GetNodeCountRecursive (this, ref count);
450 public void Remove () {
453 parent.Nodes.RemoveAt (Index);
456 public void Toggle () {
463 public override String ToString () {
464 return String.Concat ("TreeNode: ", Text);
467 #endregion // Public Instance Methods
469 #region Internal & Private Methods and Properties
471 internal bool IsRoot {
473 if (tree_view == null)
475 if (tree_view.root_node == this)
481 bool BuildFullPath (StringBuilder path)
486 if (parent.BuildFullPath (path))
487 path.Append (tree_view.PathSeparator);
494 get { return index; }
497 private void Expand (bool byInternal)
502 if (TreeView != null) {
503 TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Expand);
504 TreeView.OnBeforeExpand (e);
510 if (TreeView != null)
511 TreeView.OnAfterExpand (new TreeViewEventArgs (this));
512 if (IsVisible && TreeView != null)
513 TreeView.UpdateBelow (this);
517 private void Collapse (bool byInternal)
522 if (tree_view != null && tree_view.root_node == this)
526 if (TreeView != null) {
527 TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Collapse);
528 TreeView.OnBeforeCollapse (e);
534 if (TreeView != null)
535 TreeView.OnAfterCollapse (new TreeViewEventArgs (this));
536 if (IsVisible && TreeView != null)
537 TreeView.UpdateBelow (this);
538 if(!byInternal && TreeView != null && HasFocusInChildren ())
539 TreeView.SelectedNode = this;
543 private bool HasFocusInChildren()
545 if(TreeView == null) return false;
546 foreach(TreeNode node in nodes) {
547 if(node == TreeView.SelectedNode) return true;
548 if(node.HasFocusInChildren())
554 private void ExpandRecursive (TreeNode node)
557 foreach (TreeNode child in node.Nodes) {
558 ExpandRecursive (child);
562 private void ExpandParentRecursive (TreeNode node)
565 if (node.Parent != null)
566 ExpandParentRecursive (node.Parent);
569 internal void CollapseAll ()
571 CollapseRecursive (this);
574 internal void CollapseAllUncheck ()
576 CollapseUncheckRecursive (this);
579 private void CollapseRecursive (TreeNode node)
582 foreach (TreeNode child in node.Nodes) {
583 CollapseRecursive (child);
587 private void CollapseUncheckRecursive (TreeNode node)
590 node.Checked = false;
591 foreach (TreeNode child in node.Nodes) {
592 CollapseUncheckRecursive (child);
596 internal void SetNodes (TreeNodeCollection nodes)
601 private void GetNodeCountRecursive (TreeNode node, ref int count)
603 count += node.Nodes.Count;
604 foreach (TreeNode child in node.Nodes) {
605 GetNodeCountRecursive (child, ref count);
609 internal bool NeedsWidth {
610 get { return bounds.Width == 0; }
613 internal void InvalidateWidth ()
618 internal void SetWidth (int width)
620 bounds.Width = width;
623 internal void SetHeight (int height)
625 bounds.Height = height;
628 internal void SetPosition (int x, int y)
634 internal void SetAddedData (TreeView tree_view, TreeNode parent, int index)
636 this.tree_view = tree_view;
637 this.parent = parent;
641 internal void SetIndex (int index)
646 private bool IsInClippingRect
649 if (TreeView == null)
651 if (bounds.Y < 0 && bounds.Y > tree_view.ClientRectangle.Height)
656 #endregion // Internal & Private Methods and Properties