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)
29 using System.Runtime.Serialization;
31 namespace System.Windows.Forms {
34 public class TreeNode : MarshalByRefObject, ICloneable /*, ISerializable */ {
36 private TreeView tree_view;
37 internal TreeNode parent;
41 private int image_index = -1;
42 private int selected_image_index = -1;
43 internal TreeNodeCollection nodes;
45 private bool is_expanded = false;
46 private Rectangle bounds = Rectangle.Empty;
47 private Rectangle plus_minus_bounds = Rectangle.Empty;
48 private Rectangle checkbox_bounds = Rectangle.Empty;
50 private bool is_editing;
51 internal OwnerDrawPropertyBag prop_bag;
54 private IntPtr handle;
56 internal TreeNode (TreeView tree_view) : this ()
58 this.tree_view = tree_view;
63 nodes = new TreeNodeCollection (this);
66 public TreeNode (string text) : this ()
71 public TreeNode (string text, TreeNode [] children) : this (text)
73 Nodes.AddRange (children);
76 public TreeNode (string text, int image_index, int selected_image_index) : this (text)
78 this.image_index = image_index;
79 this.selected_image_index = selected_image_index;
82 public TreeNode (string text, int image_index, int selected_image_index,
83 TreeNode [] children) : this (text, image_index, selected_image_index)
85 Nodes.AddRange (children);
88 internal TreeView TreeView {
90 if (tree_view != null)
92 TreeNode walk = parent;
93 while (walk != null) {
94 if (walk.TreeView != null)
95 tree_view = walk.TreeView;
102 #region ICloneable Members
104 public object Clone()
106 TreeNode tn = new TreeNode (text, image_index, selected_image_index);
108 foreach (TreeNode child in nodes)
109 tn.Nodes.Add ((TreeNode)child.Clone ());
112 tn.Checked = Checked;
113 if (prop_bag != null)
114 tn.prop_bag = OwnerDrawPropertyBag.Copy (prop_bag);
120 public TreeNode Parent {
122 if (tree_view != null && tree_view.root_node == parent)
142 public Rectangle Bounds {
143 get { return bounds; }
146 internal Rectangle PlusMinusBounds {
147 get { return plus_minus_bounds; }
150 internal Rectangle CheckBoxBounds {
151 get { return checkbox_bounds; }
154 public bool Checked {
155 get { return check; }
161 if (TreeView != null)
162 tree_view.UpdateNode (this);
166 public Color BackColor {
168 if (prop_bag != null)
169 return prop_bag.BackColor;
170 if (TreeView != null)
171 return TreeView.BackColor;
175 if (prop_bag == null)
176 prop_bag = new OwnerDrawPropertyBag ();
177 prop_bag.BackColor = value;
181 public Color ForeColor {
183 if (prop_bag != null)
184 return prop_bag.ForeColor;
185 if (TreeView != null)
186 return TreeView.ForeColor;
190 if (prop_bag == null)
191 prop_bag = new OwnerDrawPropertyBag ();
192 prop_bag.ForeColor = value;
196 public Font NodeFont {
198 if (prop_bag != null)
199 return prop_bag.Font;
200 if (TreeView != null)
201 return TreeView.Font;
205 if (prop_bag == null)
206 prop_bag = new OwnerDrawPropertyBag ();
207 prop_bag.Font = value;
211 public TreeNodeCollection Nodes {
214 nodes = new TreeNodeCollection (this);
219 public TreeNode FirstNode {
227 public string FullPath {
229 if (tree_view == null)
230 throw new Exception ("No TreeView associated");
232 StringBuilder builder = new StringBuilder ();
233 BuildFullPath (builder);
234 return builder.ToString ();
238 bool BuildFullPath (StringBuilder path)
243 if (parent.BuildFullPath (path))
244 path.Append (tree_view.PathSeparator);
250 public bool IsExpanded {
251 get { return is_expanded; }
254 public TreeNode NextNode {
258 if (parent.Nodes.Count > index + 1)
259 return parent.Nodes [index + 1];
264 public TreeNode PrevNode {
268 if (index == 0 || index > parent.Nodes.Count)
270 return parent.Nodes [index - 1];
274 public TreeNode NextVisibleNode {
276 OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
279 TreeNode c = (TreeNode) o.Current;
280 if (!c.IsInClippingRect)
286 public TreeNode PrevVisibleNode {
288 OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
289 if (!o.MovePrevious ())
291 TreeNode c = (TreeNode) o.Current;
292 if (!c.IsInClippingRect)
298 public TreeNode LastNode {
300 return (nodes == null || nodes.Count == 0) ? null : nodes [nodes.Count - 1];
305 get { return index; }
308 public int ImageIndex {
309 get { return image_index; }
310 set { image_index = value; }
313 public int SelectedImageIndex {
314 get { return selected_image_index; }
315 set { selected_image_index = value; }
323 public bool IsSelected {
325 if (TreeView == null)
327 return TreeView.SelectedNode == this;
331 public bool IsEditing {
332 get { return is_editing; }
335 public bool IsVisible {
337 if (TreeView == null)
340 if (bounds.Y < 0 && bounds.Y > TreeView.ClientRectangle.Height)
343 TreeNode parent = Parent;
344 while (parent != null) {
345 if (!parent.IsExpanded)
347 parent = parent.Parent;
353 public void BeginEdit ()
358 public void EndEdit (bool cancel)
361 if (!cancel && TreeView != null)
362 text = TreeView.LabelEditText;
365 public void Expand ()
369 private void Expand (bool byInternal)
375 if (TreeView != null) {
376 TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Expand);
377 TreeView.OnBeforeCollapse (e);
383 if (TreeView != null)
384 TreeView.OnAfterCollapse (new TreeViewEventArgs (this));
385 if (IsVisible && TreeView != null)
386 TreeView.UpdateBelow (this);
390 public void Collapse ()
395 private void Collapse (bool byInternal)
400 if (tree_view != null && tree_view.root_node == this)
404 if (TreeView != null) {
405 TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Collapse);
406 TreeView.OnBeforeCollapse (e);
412 if (TreeView != null)
413 TreeView.OnAfterCollapse (new TreeViewEventArgs (this));
414 if (IsVisible && TreeView != null)
415 TreeView.UpdateBelow (this);
416 if(!byInternal && TreeView != null && HasFocusInChildren ())
417 TreeView.SelectedNode = this;
421 private bool HasFocusInChildren()
423 if(TreeView == null) return false;
424 foreach(TreeNode node in nodes) {
425 if(node == TreeView.SelectedNode) return true;
426 if(node.HasFocusInChildren())
432 public void Remove ()
436 parent.Nodes.RemoveAt (Index);
439 public void ExpandAll ()
441 ExpandRecursive (this);
446 private void ExpandRecursive (TreeNode node)
449 foreach (TreeNode child in node.Nodes) {
450 ExpandRecursive (child);
454 internal void CollapseAll ()
456 CollapseRecursive (this);
459 internal void CollapseAllUncheck ()
461 CollapseUncheckRecursive (this);
464 private void CollapseRecursive (TreeNode node)
467 foreach (TreeNode child in node.Nodes) {
468 CollapseRecursive (child);
472 private void CollapseUncheckRecursive (TreeNode node)
475 node.Checked = false;
476 foreach (TreeNode child in node.Nodes) {
477 CollapseUncheckRecursive (child);
481 public int GetNodeCount (bool include_subtrees)
483 if (!include_subtrees)
487 GetNodeCountRecursive (this, ref count);
492 public void Toggle ()
500 internal void SetNodes (TreeNodeCollection nodes)
505 private void GetNodeCountRecursive (TreeNode node, ref int count)
507 count += node.Nodes.Count;
508 foreach (TreeNode child in node.Nodes) {
509 GetNodeCountRecursive (child, ref count);
513 public override String ToString ()
515 return String.Concat ("TreeNode: ", Text);
518 internal void UpdateBounds (int x, int y, int width, int height)
522 bounds.Width = width;
523 bounds.Height = height;
526 internal void UpdatePlusMinusBounds (int x, int y, int width, int height)
528 plus_minus_bounds.X = x;
529 plus_minus_bounds.Y = y;
530 plus_minus_bounds.Width = width;
531 plus_minus_bounds.Height = height;
534 internal void UpdateCheckBoxBounds (int x, int y, int width, int height)
536 checkbox_bounds.X = x;
537 checkbox_bounds.Y = y;
538 checkbox_bounds.Width = width;
539 checkbox_bounds.Height = height;
542 internal void SetAddedData (TreeView tree_view, TreeNode parent, int index)
544 this.tree_view = tree_view;
545 this.parent = parent;
549 internal void SetIndex (int index)
554 private bool IsInClippingRect
557 if (TreeView == null)
559 if (bounds.Y < 0 && bounds.Y > tree_view.ClientRectangle.Height)