1096 lines
27 KiB
C#
Raw Normal View History

// 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 (jackson@ximian.com)
// Kazuki Oikawa (kazuki@panicode.com)
using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.Serialization;
using System.Text;
namespace System.Windows.Forms
{
[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 ContextMenu context_menu;
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 = context_menu;
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 ContextMenu ContextMenu {
get { return context_menu; }
set { context_menu = value; }
}
[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 ("System.Windows.Forms.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 ("System.Windows.Forms.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 ("System.Windows.Forms.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 ("System.Windows.Forms.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 ("System.Windows.Forms.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 ("System.Windows.Forms.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
}
}