aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/Widgets/TreeNode.cs
diff options
context:
space:
mode:
Diffstat (limited to 'source/ShiftUI/Widgets/TreeNode.cs')
-rw-r--r--source/ShiftUI/Widgets/TreeNode.cs1087
1 files changed, 1087 insertions, 0 deletions
diff --git a/source/ShiftUI/Widgets/TreeNode.cs b/source/ShiftUI/Widgets/TreeNode.cs
new file mode 100644
index 0000000..0a4a13b
--- /dev/null
+++ b/source/ShiftUI/Widgets/TreeNode.cs
@@ -0,0 +1,1087 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2004-2005 Novell, Inc.
+//
+// Authors:
+// Jackson Harper ([email protected])
+// Kazuki Oikawa ([email protected])
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Runtime.Serialization;
+using System.Text;
+
+namespace ShiftUI
+{
+ [DefaultProperty ("Text")]
+ [TypeConverter(typeof(TreeNodeConverter))]
+ [Serializable]
+ public class TreeNode : MarshalByRefObject, ICloneable, ISerializable
+ {
+ #region Fields
+ private TreeView tree_view;
+ internal TreeNode parent;
+
+ private string text;
+ private int image_index = -1;
+ private int selected_image_index = -1;
+ private ContextMenuStrip context_menu_strip;
+ private string image_key = String.Empty;
+ private string selected_image_key = String.Empty;
+ private int state_image_index = -1;
+ private string state_image_key = String.Empty;
+ private string tool_tip_text = String.Empty;
+ internal TreeNodeCollection nodes;
+ internal TreeViewAction check_reason = TreeViewAction.Unknown;
+
+ internal int visible_order = 0;
+ internal int width = -1;
+
+ internal bool is_expanded = false;
+ private bool check;
+ internal OwnerDrawPropertyBag prop_bag;
+
+ private object tag;
+
+ internal IntPtr handle;
+
+ private string name = string.Empty;
+ #endregion // Fields
+
+ #region Internal Constructors
+ internal TreeNode (TreeView tree_view) : this ()
+ {
+ this.tree_view = tree_view;
+ is_expanded = true;
+ }
+
+ protected TreeNode (SerializationInfo serializationInfo, StreamingContext context) : this ()
+ {
+ SerializationInfoEnumerator en;
+ SerializationEntry e;
+ int children;
+
+ en = serializationInfo.GetEnumerator();
+ children = 0;
+ while (en.MoveNext()) {
+ e = en.Current;
+ switch(e.Name) {
+ case "Text": Text = (string)e.Value; break;
+ case "PropBag": prop_bag = (OwnerDrawPropertyBag)e.Value; break;
+ case "ImageIndex": image_index = (int)e.Value; break;
+ case "SelectedImageIndex": selected_image_index = (int)e.Value; break;
+ case "Tag": tag = e.Value; break;
+ case "IsChecked": check = (bool)e.Value; break;
+ case "ChildCount": children = (int)e.Value; break;
+ }
+ }
+ if (children > 0) {
+ for (int i = 0; i < children; i++) {
+ TreeNode node = (TreeNode) serializationInfo.GetValue ("children" + i, typeof (TreeNode));
+ Nodes.Add (node);
+ }
+ }
+ }
+ #endregion // Internal Constructors
+
+ #region Public Constructors
+ public TreeNode ()
+ {
+ nodes = new TreeNodeCollection (this);
+ }
+
+ public TreeNode (string text) : this ()
+ {
+ Text = text;
+ }
+
+ public TreeNode (string text, TreeNode [] children) : this (text)
+ {
+ Nodes.AddRange (children);
+ }
+
+ public TreeNode (string text, int imageIndex, int selectedImageIndex) : this (text)
+ {
+ this.image_index = imageIndex;
+ this.selected_image_index = selectedImageIndex;
+ }
+
+ public TreeNode (string text, int imageIndex, int selectedImageIndex,
+ TreeNode[] children)
+ : this (text, imageIndex, selectedImageIndex)
+ {
+ Nodes.AddRange (children);
+ }
+
+ #endregion // Public Constructors
+
+ #region ICloneable Members
+ public virtual object Clone ()
+ {
+ TreeNode tn = (TreeNode)Activator.CreateInstance (GetType ());
+ tn.name = name;
+ tn.text = text;
+ tn.image_key = image_key;
+ tn.image_index = image_index;
+ tn.selected_image_index = selected_image_index;
+ tn.selected_image_key = selected_image_key;
+ tn.state_image_index = state_image_index;
+ tn.state_image_key = state_image_key;
+ tn.tag = tag;
+ tn.check = check;
+ tn.tool_tip_text = tool_tip_text;
+ tn.context_menu_strip = context_menu_strip;
+ if (nodes != null) {
+ foreach (TreeNode child in nodes)
+ tn.nodes.Add ((TreeNode)child.Clone ());
+ }
+ if (prop_bag != null)
+ tn.prop_bag = OwnerDrawPropertyBag.Copy (prop_bag);
+ return tn;
+ }
+
+ #endregion // ICloneable Members
+
+ #region ISerializable Members
+ void ISerializable.GetObjectData (SerializationInfo si, StreamingContext context)
+ {
+ si.AddValue ("Text", Text);
+ si.AddValue ("prop_bag", prop_bag, typeof (OwnerDrawPropertyBag));
+ si.AddValue ("ImageIndex", ImageIndex);
+ si.AddValue ("SelectedImageIndex", SelectedImageIndex);
+ si.AddValue ("Tag", Tag);
+ si.AddValue ("Checked", Checked);
+
+ si.AddValue ("NumberOfChildren", Nodes.Count);
+ for (int i = 0; i < Nodes.Count; i++)
+ si.AddValue ("Child-" + i, Nodes [i], typeof (TreeNode));
+ }
+
+ protected virtual void Deserialize (SerializationInfo serializationInfo, StreamingContext context)
+ {
+ Text = serializationInfo.GetString ("Text");
+ prop_bag = (OwnerDrawPropertyBag)serializationInfo.GetValue ("prop_bag", typeof (OwnerDrawPropertyBag));
+ ImageIndex = serializationInfo.GetInt32 ("ImageIndex");
+ SelectedImageIndex = serializationInfo.GetInt32 ("SelectedImageIndex");
+ Tag = serializationInfo.GetValue ("Tag", typeof (Object));
+ Checked = serializationInfo.GetBoolean ("Checked");
+
+ int count = serializationInfo.GetInt32 ("NumberOfChildren");
+
+ for (int i = 0; i < count; i++)
+ Nodes.Add ((TreeNode)serializationInfo.GetValue ("Child-" + i, typeof (TreeNode)));
+ }
+
+ protected virtual void Serialize (SerializationInfo si, StreamingContext context)
+ {
+ si.AddValue ("Text", Text);
+ si.AddValue ("prop_bag", prop_bag, typeof (OwnerDrawPropertyBag));
+ si.AddValue ("ImageIndex", ImageIndex);
+ si.AddValue ("SelectedImageIndex", SelectedImageIndex);
+ si.AddValue ("Tag", Tag);
+ si.AddValue ("Checked", Checked);
+
+ si.AddValue ("NumberOfChildren", Nodes.Count);
+ for (int i = 0; i < Nodes.Count; i++)
+ si.AddValue ("Child-" + i, Nodes[i], typeof (TreeNode));
+ }
+ #endregion // ISerializable Members
+
+ #region Public Instance Properties
+ public Color BackColor {
+ get {
+ if (prop_bag != null)
+ return prop_bag.BackColor;
+ return Color.Empty;
+ }
+ set {
+ if (prop_bag == null)
+ prop_bag = new OwnerDrawPropertyBag ();
+ prop_bag.BackColor = value;
+
+ TreeView tree_view = TreeView;
+ if (tree_view != null)
+ tree_view.UpdateNode (this);
+ }
+ }
+
+ [Browsable (false)]
+ public Rectangle Bounds {
+ get {
+ if (TreeView == null)
+ return Rectangle.Empty;
+
+ int x = GetX ();
+ int y = GetY ();
+
+ if (width == -1)
+ width = TreeView.GetNodeWidth (this);
+
+ Rectangle res = new Rectangle (x, y, width, TreeView.ActualItemHeight);
+ return res;
+ }
+ }
+
+ internal int GetY ()
+ {
+ if (TreeView == null)
+ return 0;
+ return (visible_order - 1) * TreeView.ActualItemHeight - (TreeView.skipped_nodes * TreeView.ActualItemHeight);
+ }
+
+ internal int GetX ()
+ {
+ if (TreeView == null)
+ return 0;
+ int indent_level = IndentLevel;
+ int roots = (TreeView.ShowRootLines ? 1 : 0);
+ int cb = (TreeView.CheckBoxes ? 19 : 0);
+ if (!TreeView.CheckBoxes && StateImage != null)
+ cb = 19;
+ int imgs = (TreeView.ImageList != null ? TreeView.ImageList.ImageSize.Width + 3 : 0);
+ return ((indent_level + roots) * TreeView.Indent) + cb + imgs - TreeView.hbar_offset;
+ }
+
+ internal int GetLinesX ()
+ {
+ int roots = (TreeView.ShowRootLines ? 1 : 0);
+ return (IndentLevel + roots) * TreeView.Indent - TreeView.hbar_offset;
+ }
+
+ internal int GetImageX ()
+ {
+ return GetLinesX () + (TreeView.CheckBoxes || StateImage != null ? 19 : 0);
+ }
+
+ // In theory we should be able to track this instead of computing
+ // every single time we need it, however for now I am going to
+ // do it this way to reduce bugs in my new bounds computing code
+ internal int IndentLevel {
+ get {
+ TreeNode walk = this;
+ int res = 0;
+ while (walk.Parent != null) {
+ walk = walk.Parent;
+ res++;
+ }
+
+ return res;
+ }
+ }
+
+ [DefaultValue (false)]
+ public bool Checked {
+ get { return check; }
+ set {
+ if (check == value)
+ return;
+ TreeViewCancelEventArgs args = new TreeViewCancelEventArgs (this, false, check_reason);
+ if (TreeView != null)
+ TreeView.OnBeforeCheck (args);
+ if (!args.Cancel) {
+ check = value;
+
+ // TreeView can become null after OnAfterCheck, this the double null check
+ if (TreeView != null)
+ TreeView.OnAfterCheck (new TreeViewEventArgs (this, check_reason));
+ if (TreeView != null)
+ TreeView.UpdateNode (this);
+ }
+ check_reason = TreeViewAction.Unknown;
+ }
+ }
+
+ [DefaultValue (null)]
+ public virtual ContextMenuStrip ContextMenuStrip {
+ get { return context_menu_strip; }
+ set { context_menu_strip = value; }
+ }
+
+ [Browsable (false)]
+ public TreeNode FirstNode {
+ get {
+ if (nodes.Count > 0)
+ return nodes [0];
+ return null;
+ }
+ }
+
+ public Color ForeColor {
+ get {
+ if (prop_bag != null)
+ return prop_bag.ForeColor;
+ if (TreeView != null)
+ return TreeView.ForeColor;
+ return Color.Empty;
+ }
+ set {
+ if (prop_bag == null)
+ prop_bag = new OwnerDrawPropertyBag ();
+ prop_bag.ForeColor = value;
+
+ TreeView tree_view = TreeView;
+ if (tree_view != null)
+ tree_view.UpdateNode (this);
+ }
+ }
+
+ [Browsable (false)]
+ public string FullPath {
+ get {
+ if (TreeView == null)
+ throw new InvalidOperationException ("No TreeView associated");
+
+ StringBuilder builder = new StringBuilder ();
+ BuildFullPath (builder);
+ return builder.ToString ();
+ }
+ }
+
+ [DefaultValue (-1)]
+ [RelatedImageList ("TreeView.ImageList")]
+ [TypeConverter (typeof (TreeViewImageIndexConverter))]
+ [RefreshProperties (RefreshProperties.Repaint)]
+ //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
+ [Localizable(true)]
+ public int ImageIndex {
+ get { return image_index; }
+ set {
+ if (image_index == value)
+ return;
+ image_index = value;
+ image_key = string.Empty;
+ TreeView tree = TreeView;
+ if (tree != null)
+ tree.UpdateNode (this);
+ }
+ }
+
+ [Localizable(true)]
+ [DefaultValue ("")]
+ [RelatedImageList ("TreeView.ImageList")]
+ [TypeConverter (typeof (TreeViewImageKeyConverter))]
+ [RefreshProperties (RefreshProperties.Repaint)]
+ //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
+ public string ImageKey {
+ get { return image_key; }
+ set {
+ if (image_key == value)
+ return;
+ image_key = value;
+ image_index = -1;
+
+ TreeView tree = TreeView;
+ if (tree != null)
+ tree.UpdateNode(this);
+ }
+ }
+
+ [Browsable (false)]
+ public bool IsEditing {
+ get {
+ TreeView tv = TreeView;
+ if (tv == null)
+ return false;
+ return tv.edit_node == this;
+ }
+ }
+
+ [Browsable (false)]
+ public bool IsExpanded {
+ get {
+ TreeView tv = TreeView;
+
+ if (tv != null && tv.IsHandleCreated) {
+ // This is ridiculous
+ bool found = false;
+ foreach (TreeNode walk in TreeView.Nodes) {
+ if (walk.Nodes.Count > 0)
+ found = true;
+ }
+
+ if (!found)
+ return false;
+ }
+
+ return is_expanded;
+ }
+ }
+
+ [Browsable (false)]
+ public bool IsSelected {
+ get {
+ if (TreeView == null || !TreeView.IsHandleCreated)
+ return false;
+ return TreeView.SelectedNode == this;
+ }
+ }
+
+ [Browsable (false)]
+ public bool IsVisible {
+ get {
+ if (TreeView == null || !TreeView.IsHandleCreated || !TreeView.Visible)
+ return false;
+
+ if (visible_order <= TreeView.skipped_nodes || visible_order - TreeView.skipped_nodes > TreeView.VisibleCount)
+ return false;
+
+ return ArePreviousNodesExpanded;
+ }
+ }
+
+ [Browsable (false)]
+ public TreeNode LastNode {
+ get {
+ return (nodes == null || nodes.Count == 0) ? null : nodes [nodes.Count - 1];
+ }
+ }
+
+ [Browsable (false)]
+ public int Level {
+ get { return IndentLevel; }
+ }
+
+ public string Name
+ {
+ get { return this.name; }
+ set {
+ // Value should never be null as per spec
+ this.name = (value == null) ? string.Empty : value;
+ }
+ }
+
+ [Browsable (false)]
+ public TreeNode NextNode {
+ get {
+ if (parent == null)
+ return null;
+ int index = Index;
+ if (parent.Nodes.Count > index + 1)
+ return parent.Nodes [index + 1];
+ return null;
+ }
+ }
+
+ [Browsable (false)]
+ public TreeNode NextVisibleNode {
+ get {
+ OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
+ o.MoveNext (); // move to the node itself
+
+ if (!o.MoveNext ())
+ return null;
+ TreeNode c = o.CurrentNode;
+ if (!c.IsInClippingRect)
+ return null;
+ return c;
+ }
+ }
+
+ [DefaultValue (null)]
+ [Localizable (true)]
+ public Font NodeFont {
+ get {
+ if (prop_bag != null)
+ return prop_bag.Font;
+ if (TreeView != null)
+ return TreeView.Font;
+ return null;
+ }
+ set {
+ if (prop_bag == null)
+ prop_bag = new OwnerDrawPropertyBag ();
+ prop_bag.Font = value;
+ Invalidate ();
+ }
+ }
+
+ [Browsable (false)]
+ [ListBindable (false)]
+ public TreeNodeCollection Nodes {
+ get {
+ if (nodes == null)
+ nodes = new TreeNodeCollection (this);
+ return nodes;
+ }
+ }
+
+ [Browsable (false)]
+ public TreeNode Parent {
+ get {
+ TreeView tree_view = TreeView;
+ if (tree_view != null && tree_view.root_node == parent)
+ return null;
+ return parent;
+ }
+ }
+
+ [Browsable (false)]
+ public TreeNode PrevNode {
+ get {
+ if (parent == null)
+ return null;
+ int index = Index;
+ if (index <= 0 || index > parent.Nodes.Count)
+ return null;
+ return parent.Nodes [index - 1];
+ }
+ }
+
+ [Browsable (false)]
+ public TreeNode PrevVisibleNode {
+ get {
+ OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
+ o.MovePrevious (); // move to the node itself
+
+ if (!o.MovePrevious ())
+ return null;
+ TreeNode c = o.CurrentNode;
+ if (!c.IsInClippingRect)
+ return null;
+ return c;
+ }
+ }
+
+ [DefaultValue (-1)]
+ [RelatedImageList ("TreeView.ImageList")]
+ [TypeConverter (typeof (TreeViewImageIndexConverter))]
+ [RefreshProperties (RefreshProperties.Repaint)]
+ //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
+ [Localizable (true)]
+ public int SelectedImageIndex {
+ get { return selected_image_index; }
+ set { selected_image_index = value; }
+ }
+
+ [Localizable (true)]
+ [DefaultValue ("")]
+ [RelatedImageList ("TreeView.ImageList")]
+ [TypeConverter (typeof (TreeViewImageKeyConverter))]
+ [RefreshProperties (RefreshProperties.Repaint)]
+ //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
+ public string SelectedImageKey {
+ get { return selected_image_key; }
+ set { selected_image_key = value; }
+ }
+
+ [Localizable (true)]
+ [DefaultValue (-1)]
+ [RelatedImageList ("TreeView.StateImageList")]
+ [TypeConverter (typeof (NoneExcludedImageIndexConverter))]
+ [RefreshProperties (RefreshProperties.Repaint)]
+ //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
+ public int StateImageIndex {
+ get { return state_image_index; }
+ set {
+ if (state_image_index != value) {
+ state_image_index = value;
+ state_image_key = string.Empty;
+ Invalidate ();
+ }
+ }
+ }
+
+ [Localizable (true)]
+ [DefaultValue ("")]
+ [RelatedImageList ("TreeView.StateImageList")]
+ [TypeConverter (typeof (ImageKeyConverter))]
+ [RefreshProperties (RefreshProperties.Repaint)]
+ //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
+ public string StateImageKey {
+ get { return state_image_key; }
+ set {
+ if (state_image_key != value) {
+ state_image_key = value;
+ state_image_index = -1;
+ Invalidate ();
+ }
+ }
+ }
+
+ [Bindable(true)]
+ [Localizable(false)]
+ [TypeConverter(typeof(System.ComponentModel.StringConverter))]
+ [DefaultValue(null)]
+ public object Tag {
+ get { return tag; }
+ set { tag = value; }
+ }
+
+ [Localizable(true)]
+ public string Text {
+ get {
+ if (text == null)
+ return String.Empty;
+ return text;
+ }
+ set {
+ if (text == value)
+ return;
+ text = value;
+ Invalidate ();
+ // UIA Framework Event: Text Changed
+ TreeView view = TreeView;
+ if (view != null)
+ view.OnUIANodeTextChanged (new TreeViewEventArgs (this));
+ }
+ }
+
+ [DefaultValue ("")]
+ [Localizable (false)]
+ public string ToolTipText {
+ get { return tool_tip_text; }
+ set { tool_tip_text = value; }
+ }
+
+ [Browsable (false)]
+ public TreeView TreeView {
+ get {
+ if (tree_view != null)
+ return tree_view;
+ TreeNode walk = parent;
+ while (walk != null) {
+ if (walk.TreeView != null)
+ break;
+ walk = walk.parent;
+ }
+ if (walk == null)
+ return null;
+ return walk.TreeView;
+ }
+ }
+
+ [Browsable (false)]
+ public IntPtr Handle {
+ get {
+ // MS throws a NullReferenceException if the TreeView isn't set...
+ if (handle == IntPtr.Zero && TreeView != null)
+ handle = TreeView.CreateNodeHandle ();
+ return handle;
+ }
+ }
+
+ #endregion // Public Instance Properties
+
+
+ public static TreeNode FromHandle (TreeView tree, IntPtr handle)
+ {
+ if (handle == IntPtr.Zero)
+ return null;
+ // No arg checking on MS it just throws a NullRef if treeview is null
+ return tree.NodeFromHandle (handle);
+ }
+
+ #region Public Instance Methods
+ public void BeginEdit ()
+ {
+ TreeView tv = TreeView;
+ if (tv != null)
+ tv.BeginEdit (this);
+ }
+
+ public void Collapse ()
+ {
+ CollapseInternal (false);
+ }
+
+ public void Collapse (bool ignoreChildren)
+ {
+ if (ignoreChildren)
+ Collapse ();
+ else
+ CollapseRecursive (this);
+ }
+
+ public void EndEdit (bool cancel)
+ {
+ TreeView tv = TreeView;
+ if (!cancel && tv != null)
+ tv.EndEdit (this);
+ else if (cancel && tv != null)
+ tv.CancelEdit (this);
+ }
+
+ public void Expand ()
+ {
+ Expand (false);
+ }
+
+ public void ExpandAll ()
+ {
+ ExpandRecursive (this);
+ if(TreeView != null)
+ TreeView.UpdateNode (TreeView.root_node);
+ }
+
+ public void EnsureVisible ()
+ {
+ if (TreeView == null)
+ return;
+
+ if (this.Parent != null)
+ ExpandParentRecursive (this.Parent);
+
+ Rectangle bounds = Bounds;
+ if (bounds.Y < 0) {
+ TreeView.SetTop (this);
+ } else if (bounds.Bottom > TreeView.ViewportRectangle.Bottom) {
+ TreeView.SetBottom (this);
+ }
+ }
+
+ public int GetNodeCount (bool includeSubTrees)
+ {
+ if (!includeSubTrees)
+ return Nodes.Count;
+
+ int count = 0;
+ GetNodeCountRecursive (this, ref count);
+
+ return count;
+ }
+
+ public void Remove ()
+ {
+ if (parent == null)
+ return;
+ int index = Index;
+ parent.Nodes.RemoveAt (index);
+ }
+
+ public void Toggle ()
+ {
+ if (is_expanded)
+ Collapse ();
+ else
+ Expand ();
+ }
+
+ public override String ToString ()
+ {
+ return String.Concat ("TreeNode: ", Text);
+ }
+
+ #endregion // Public Instance Methods
+
+ #region Internal & Private Methods and Properties
+
+ internal bool ArePreviousNodesExpanded {
+ get {
+ TreeNode parent = Parent;
+ while (parent != null) {
+ if (!parent.is_expanded)
+ return false;
+ parent = parent.Parent;
+ }
+
+ return true;
+ }
+ }
+
+ internal bool IsRoot {
+ get {
+ TreeView tree_view = TreeView;
+ if (tree_view == null)
+ return false;
+ if (tree_view.root_node == this)
+ return true;
+ return false;
+ }
+ }
+
+ bool BuildFullPath (StringBuilder path)
+ {
+ if (parent == null)
+ return false;
+
+ if (parent.BuildFullPath (path))
+ path.Append (TreeView.PathSeparator);
+
+ path.Append (text);
+ return true;
+ }
+
+ public int Index {
+ get {
+ if (parent == null)
+ return 0;
+ return parent.Nodes.IndexOf (this);
+ }
+ }
+
+ private void Expand (bool byInternal)
+ {
+ if (is_expanded || nodes.Count < 1) {
+ is_expanded = true;
+ return;
+ }
+
+ bool cancel = false;
+ TreeView tree_view = TreeView;
+ if (tree_view != null) {
+ TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Expand);
+ tree_view.OnBeforeExpand (e);
+ cancel = e.Cancel;
+ }
+
+ if (!cancel) {
+ is_expanded = true;
+ int count_to_next = CountToNext ();
+
+ if (tree_view != null) {
+ tree_view.OnAfterExpand (new TreeViewEventArgs (this));
+
+ tree_view.RecalculateVisibleOrder (this);
+ tree_view.UpdateScrollBars (false);
+
+ // ExpandBelow if we affect the visible area
+ if (visible_order < tree_view.skipped_nodes + tree_view.VisibleCount + 1 && ArePreviousNodesExpanded)
+ tree_view.ExpandBelow (this, count_to_next);
+ }
+ }
+ }
+
+ private void CollapseInternal (bool byInternal)
+ {
+ if (!is_expanded || nodes.Count < 1)
+ return;
+
+ if (IsRoot)
+ return;
+
+ bool cancel = false;
+ TreeView tree_view = TreeView;
+ if (tree_view != null) {
+ TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Collapse);
+ tree_view.OnBeforeCollapse (e);
+ cancel = e.Cancel;
+ }
+
+ if (!cancel) {
+ int count_to_next = CountToNext ();
+
+ is_expanded = false;
+
+ if (tree_view != null) {
+ tree_view.OnAfterCollapse (new TreeViewEventArgs (this));
+
+ bool hbar_visible = tree_view.hbar.Visible;
+ bool vbar_visible = tree_view.vbar.Visible;
+
+ tree_view.RecalculateVisibleOrder (this);
+ tree_view.UpdateScrollBars (false);
+
+ // CollapseBelow if we affect the visible area
+ if (visible_order < tree_view.skipped_nodes + tree_view.VisibleCount + 1 && ArePreviousNodesExpanded)
+ tree_view.CollapseBelow (this, count_to_next);
+ if(!byInternal && HasFocusInChildren ())
+ tree_view.SelectedNode = this;
+
+ // If one or both of our scrollbars disappeared,
+ // invalidate everything
+ if ((hbar_visible & !tree_view.hbar.Visible) || (vbar_visible & !tree_view.vbar.Visible))
+ tree_view.Invalidate ();
+ }
+ }
+ }
+
+ private int CountToNext ()
+ {
+ bool expanded = is_expanded;
+ is_expanded = false;
+ OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (this);
+
+ TreeNode next= null;
+ if (walk.MoveNext () && walk.MoveNext ())
+ next = walk.CurrentNode;
+
+ is_expanded = expanded;
+ walk.Reset ();
+ walk.MoveNext ();
+
+ int count = 0;
+ while (walk.MoveNext () && walk.CurrentNode != next)
+ count++;
+
+ return count;
+ }
+
+ private bool HasFocusInChildren()
+ {
+ if (TreeView == null)
+ return false;
+ foreach (TreeNode node in nodes) {
+ if(node == TreeView.SelectedNode)
+ return true;
+ if(node.HasFocusInChildren ())
+ return true;
+ }
+ return false;
+ }
+
+ private void ExpandRecursive (TreeNode node)
+ {
+ node.Expand (true);
+ foreach (TreeNode child in node.Nodes)
+ ExpandRecursive (child);
+ }
+
+ private void ExpandParentRecursive (TreeNode node)
+ {
+ node.Expand (true);
+ if (node.Parent != null)
+ ExpandParentRecursive (node.Parent);
+ }
+
+ internal void CollapseAll ()
+ {
+ CollapseRecursive (this);
+ }
+
+ internal void CollapseAllUncheck ()
+ {
+ CollapseUncheckRecursive (this);
+ }
+
+ private void CollapseRecursive (TreeNode node)
+ {
+ node.Collapse ();
+ foreach (TreeNode child in node.Nodes)
+ CollapseRecursive (child);
+ }
+
+ private void CollapseUncheckRecursive (TreeNode node)
+ {
+ node.Collapse ();
+ node.Checked = false;
+ foreach (TreeNode child in node.Nodes)
+ CollapseUncheckRecursive (child);
+ }
+
+ internal void SetNodes (TreeNodeCollection nodes)
+ {
+ this.nodes = nodes;
+ }
+
+ private void GetNodeCountRecursive (TreeNode node, ref int count)
+ {
+ count += node.Nodes.Count;
+ foreach (TreeNode child in node.Nodes)
+ GetNodeCountRecursive (child, ref count);
+ }
+
+ internal bool NeedsWidth {
+ get { return width == -1; }
+ }
+
+ internal void Invalidate ()
+ {
+ // invalidate width first so Bounds retrieves
+ // the updated value (we don't use it here however)
+ width = -1;
+
+ TreeView tv = TreeView;
+ if (tv == null)
+ return;
+
+ tv.UpdateNode (this);
+ }
+
+ internal void InvalidateWidth ()
+ {
+ // bounds.Width = 0;
+ width = -1;
+ }
+
+ internal void SetWidth (int width)
+ {
+ this.width = width;
+ }
+
+ internal void SetParent (TreeNode parent)
+ {
+ this.parent = parent;
+ }
+
+ private bool IsInClippingRect {
+ get {
+ if (TreeView == null)
+ return false;
+ Rectangle bounds = Bounds;
+ if (bounds.Y < 0 && bounds.Y > TreeView.ClientRectangle.Height)
+ return false;
+ return true;
+ }
+ }
+
+ internal Image StateImage {
+ get {
+ if (TreeView != null) {
+ if (TreeView.StateImageList == null)
+ return null;
+ if (state_image_index >= 0)
+ return TreeView.StateImageList.Images[state_image_index];
+ if (state_image_key != string.Empty)
+ return TreeView.StateImageList.Images[state_image_key];
+ }
+
+ return null;
+ }
+ }
+
+ // Order of operation:
+ // 1) Node.Image[Key|Index]
+ // 2) TreeView.Image[Key|Index]
+ // 3) First image in TreeView.ImageList
+ internal int Image {
+ get {
+ if (TreeView == null || TreeView.ImageList == null)
+ return -1;
+
+ if (IsSelected) {
+ if (selected_image_index >= 0)
+ return selected_image_index;
+ if (!string.IsNullOrEmpty (selected_image_key))
+ return TreeView.ImageList.Images.IndexOfKey (selected_image_key);
+ if (!string.IsNullOrEmpty (TreeView.SelectedImageKey))
+ return TreeView.ImageList.Images.IndexOfKey (TreeView.SelectedImageKey);
+ if (TreeView.SelectedImageIndex >= 0)
+ return TreeView.SelectedImageIndex;
+ } else {
+ if (image_index >= 0)
+ return image_index;
+ if (!string.IsNullOrEmpty (image_key))
+ return TreeView.ImageList.Images.IndexOfKey (image_key);
+ if (!string.IsNullOrEmpty (TreeView.ImageKey))
+ return TreeView.ImageList.Images.IndexOfKey (TreeView.ImageKey);
+ if (TreeView.ImageIndex >= 0)
+ return TreeView.ImageIndex;
+ }
+
+ if (TreeView.ImageList.Images.Count > 0)
+ return 0;
+
+ return -1;
+ }
+ }
+ #endregion // Internal & Private Methods and Properties
+ }
+}