diff options
Diffstat (limited to 'source/ShiftUI/Widgets/TreeNode.cs')
| -rw-r--r-- | source/ShiftUI/Widgets/TreeNode.cs | 1087 |
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 + } +} |
