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;
48 private Rectangle plus_minus_bounds = Rectangle.Empty;
49 private Rectangle checkbox_bounds = Rectangle.Empty;
51 private bool is_editing;
52 internal OwnerDrawPropertyBag prop_bag;
55 private IntPtr handle;
58 #region Internal Constructors
59 internal TreeNode (TreeView tree_view) : this ()
61 this.tree_view = tree_view;
64 #endregion // Internal Constructors
66 #region Public Constructors
69 nodes = new TreeNodeCollection (this);
72 public TreeNode (string text) : this ()
77 public TreeNode (string text, TreeNode [] children) : this (text)
79 Nodes.AddRange (children);
82 public TreeNode (string text, int image_index, int selected_image_index) : this (text)
84 this.image_index = image_index;
85 this.selected_image_index = selected_image_index;
88 public TreeNode (string text, int image_index, int selected_image_index,
89 TreeNode [] children) : this (text, image_index, selected_image_index)
91 Nodes.AddRange (children);
94 #endregion // Public Constructors
96 #region ICloneable Members
99 TreeNode tn = new TreeNode (text, image_index, selected_image_index);
101 foreach (TreeNode child in nodes)
102 tn.Nodes.Add ((TreeNode)child.Clone ());
105 tn.Checked = Checked;
106 if (prop_bag != null)
107 tn.prop_bag = OwnerDrawPropertyBag.Copy (prop_bag);
111 #endregion // ICloneable Members
113 #region ISerializable Members
115 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
116 throw new NotImplementedException();
118 #endregion // ISerializable Members
120 #region Public Instance Properties
121 public Color BackColor {
123 if (prop_bag != null)
124 return prop_bag.BackColor;
125 if (TreeView != null)
126 return TreeView.BackColor;
130 if (prop_bag == null)
131 prop_bag = new OwnerDrawPropertyBag ();
132 prop_bag.BackColor = value;
136 public Rectangle Bounds {
137 get { return bounds; }
140 public bool Checked {
141 get { return check; }
147 if (TreeView != null)
148 tree_view.UpdateNode (this);
152 public TreeNode FirstNode {
160 public Color ForeColor {
162 if (prop_bag != null)
163 return prop_bag.ForeColor;
164 if (TreeView != null)
165 return TreeView.ForeColor;
169 if (prop_bag == null)
170 prop_bag = new OwnerDrawPropertyBag ();
171 prop_bag.ForeColor = value;
175 public string FullPath {
177 if (tree_view == null)
178 throw new Exception ("No TreeView associated");
180 StringBuilder builder = new StringBuilder ();
181 BuildFullPath (builder);
182 return builder.ToString ();
187 public int ImageIndex {
188 get { return image_index; }
189 set { image_index = value; }
192 public bool IsEditing {
193 get { return is_editing; }
196 public bool IsExpanded {
197 get { return is_expanded; }
200 public bool IsSelected {
202 if (TreeView == null)
204 return TreeView.SelectedNode == this;
208 public bool IsVisible {
210 if (TreeView == null)
213 if (bounds.Y < 0 && bounds.Y > TreeView.ClientRectangle.Height)
216 TreeNode parent = Parent;
217 while (parent != null) {
218 if (!parent.IsExpanded)
220 parent = parent.Parent;
226 public TreeNode LastNode {
228 return (nodes == null || nodes.Count == 0) ? null : nodes [nodes.Count - 1];
232 public TreeNode NextNode {
236 if (parent.Nodes.Count > index + 1)
237 return parent.Nodes [index + 1];
242 public TreeNode NextVisibleNode {
244 OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
247 TreeNode c = (TreeNode) o.Current;
248 if (!c.IsInClippingRect)
255 public Font NodeFont {
257 if (prop_bag != null)
258 return prop_bag.Font;
259 if (TreeView != null)
260 return TreeView.Font;
264 if (prop_bag == null)
265 prop_bag = new OwnerDrawPropertyBag ();
266 prop_bag.Font = value;
270 [ListBindable(false)]
271 public TreeNodeCollection Nodes {
274 nodes = new TreeNodeCollection (this);
279 public TreeNode Parent {
281 if (tree_view != null && tree_view.root_node == parent)
287 public TreeNode PrevNode {
291 if (index == 0 || index > parent.Nodes.Count)
293 return parent.Nodes [index - 1];
297 public TreeNode PrevVisibleNode {
299 OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
300 if (!o.MovePrevious ())
302 TreeNode c = (TreeNode) o.Current;
303 if (!c.IsInClippingRect)
310 public int SelectedImageIndex {
311 get { return selected_image_index; }
312 set { selected_image_index = value; }
317 [TypeConverter(typeof(System.ComponentModel.StringConverter))]
339 public TreeView TreeView {
341 if (tree_view != null)
343 TreeNode walk = parent;
344 while (walk != null) {
345 if (walk.TreeView != null)
346 tree_view = walk.TreeView;
353 #endregion // Public Instance Properties
355 #region Public Static Methods
356 #endregion // Public Static Methods
358 #region Public Instance Methods
359 public void BeginEdit () {
363 public void Collapse () {
367 public void EndEdit (bool cancel) {
369 if (!cancel && TreeView != null)
370 text = TreeView.LabelEditText;
373 public void Expand () {
377 public void ExpandAll () {
378 ExpandRecursive (this);
383 public int GetNodeCount (bool include_subtrees) {
384 if (!include_subtrees)
388 GetNodeCountRecursive (this, ref count);
393 public void Remove () {
396 parent.Nodes.RemoveAt (Index);
399 public void Toggle () {
406 public override String ToString () {
407 return String.Concat ("TreeNode: ", Text);
410 #endregion // Public Instance Methods
412 #region Internal & Private Methods and Properties
413 internal Rectangle PlusMinusBounds {
414 get { return plus_minus_bounds; }
417 internal Rectangle CheckBoxBounds {
418 get { return checkbox_bounds; }
421 bool BuildFullPath (StringBuilder path)
426 if (parent.BuildFullPath (path))
427 path.Append (tree_view.PathSeparator);
434 get { return index; }
437 private void Expand (bool byInternal)
443 if (TreeView != null) {
444 TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Expand);
445 TreeView.OnBeforeCollapse (e);
451 if (TreeView != null)
452 TreeView.OnAfterCollapse (new TreeViewEventArgs (this));
453 if (IsVisible && TreeView != null)
454 TreeView.UpdateBelow (this);
458 private void Collapse (bool byInternal)
463 if (tree_view != null && tree_view.root_node == this)
467 if (TreeView != null) {
468 TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Collapse);
469 TreeView.OnBeforeCollapse (e);
475 if (TreeView != null)
476 TreeView.OnAfterCollapse (new TreeViewEventArgs (this));
477 if (IsVisible && TreeView != null)
478 TreeView.UpdateBelow (this);
479 if(!byInternal && TreeView != null && HasFocusInChildren ())
480 TreeView.SelectedNode = this;
484 private bool HasFocusInChildren()
486 if(TreeView == null) return false;
487 foreach(TreeNode node in nodes) {
488 if(node == TreeView.SelectedNode) return true;
489 if(node.HasFocusInChildren())
495 private void ExpandRecursive (TreeNode node)
498 foreach (TreeNode child in node.Nodes) {
499 ExpandRecursive (child);
503 internal void CollapseAll ()
505 CollapseRecursive (this);
508 internal void CollapseAllUncheck ()
510 CollapseUncheckRecursive (this);
513 private void CollapseRecursive (TreeNode node)
516 foreach (TreeNode child in node.Nodes) {
517 CollapseRecursive (child);
521 private void CollapseUncheckRecursive (TreeNode node)
524 node.Checked = false;
525 foreach (TreeNode child in node.Nodes) {
526 CollapseUncheckRecursive (child);
530 internal void SetNodes (TreeNodeCollection nodes)
535 private void GetNodeCountRecursive (TreeNode node, ref int count)
537 count += node.Nodes.Count;
538 foreach (TreeNode child in node.Nodes) {
539 GetNodeCountRecursive (child, ref count);
543 internal void UpdateBounds (int x, int y, int width, int height)
547 bounds.Width = width;
548 bounds.Height = height;
551 internal void UpdatePlusMinusBounds (int x, int y, int width, int height)
553 plus_minus_bounds.X = x;
554 plus_minus_bounds.Y = y;
555 plus_minus_bounds.Width = width;
556 plus_minus_bounds.Height = height;
559 internal void UpdateCheckBoxBounds (int x, int y, int width, int height)
561 checkbox_bounds.X = x;
562 checkbox_bounds.Y = y;
563 checkbox_bounds.Width = width;
564 checkbox_bounds.Height = height;
567 internal void SetAddedData (TreeView tree_view, TreeNode parent, int index)
569 this.tree_view = tree_view;
570 this.parent = parent;
574 internal void SetIndex (int index)
579 private bool IsInClippingRect
582 if (TreeView == null)
584 if (bounds.Y < 0 && bounds.Y > tree_view.ClientRectangle.Height)
589 #endregion // Internal & Private Methods and Properties