using System;
using System.Drawing;
using System.Text;
using DevComponents.AdvTree.Display;
using System.Collections;
namespace DevComponents.AdvTree
{
///
/// Represents node operations.
///
internal class NodeOperations
{
///
/// Returns full path to the given node.
///
/// Node to return path to.
/// Full path to the node.
public static string GetFullPath(Node node,string pathSeparator)
{
if(node==null)
throw new ArgumentNullException("node");
StringBuilder sb=new StringBuilder(node.Text);
node=node.Parent;
while(node!=null)
{
sb.Insert(0, node.Text + pathSeparator);
node=node.Parent;
}
return sb.ToString();
}
///
/// Gets the last child tree node. The LastNode is the last child Node in the NodeCollection stored in the Nodes property of the current tree node. If the Node has no child tree node, the LastNode property returns a null reference (Nothing in Visual Basic).
///
/// Reference node.
/// Last node if found or null if there is no last node.
public static Node GetLastNode(Node node)
{
if(node.Nodes.Count>0)
{
return node.Nodes[node.Nodes.Count-1];
}
return null;
}
///
/// Returns last rendered node on screen.
///
/// Tree control.
/// Last rendered node or null
public static Node GetLastDisplayedNode(AdvTree tree)
{
Rectangle r = tree.NodeLayout.ClientArea;
Node node = tree.SelectedNode;
if (node == null) node = GetFirstVisibleNode(tree);
Point scrollPos = Point.Empty;
if (tree.AutoScroll)
scrollPos = tree.GetAutoScrollPositionOffset();
// Find last fully rendered node
Node lastNode = null;
if (r.IntersectsWith(node.Bounds))
lastNode = node;
while (node != null)
{
node = NodeOperations.GetNextVisibleNode(node);
if (node != null && node.Selectable)
{
Rectangle nodeRect = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeContentBounds, node, scrollPos);
if (nodeRect.Bottom > r.Bottom)
break;
else if (r.IntersectsWith(nodeRect))
lastNode = node;
}
}
return lastNode;
}
///
/// Returns first rendered node on screen.
///
/// Tree control.
/// Last rendered node or null
public static Node GetFirstDisplayedNode(AdvTree tree)
{
Rectangle r = tree.GetInnerRectangle();
r.Y += tree.ColumnHeaderHeight;
r.Height -= tree.ColumnHeaderHeight;
Node node = tree.SelectedNode;
if (node == null) node = GetFirstVisibleNode(tree);
Point scrollPos = Point.Empty;
if (tree.AutoScroll)
scrollPos = tree.GetAutoScrollPositionOffset();
// Find last fully rendered node
Node lastNode = null;
if (r.IntersectsWith(node.Bounds))
lastNode = node;
while (node != null)
{
node = NodeOperations.GetPreviousVisibleNode(node);
if (node != null && node.Selectable)
{
Rectangle nodeRect = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeContentBounds, node, scrollPos);
if (r.IntersectsWith(nodeRect))
lastNode = node;
else if (nodeRect.Y < r.Y)
break;
}
}
return lastNode;
}
///
/// Gets first visible node.
///
/// Reference to tree.
/// Last visible node found or null
public static Node GetFirstVisibleNode(AdvTree tree)
{
if (tree.Nodes.Count == 0) return null;
Node node = tree.DisplayRootNode == null ? tree.Nodes[0] : tree.DisplayRootNode;
if (node.Visible)
return node;
return GetNextVisibleNode(node);
}
///
/// Gets last visible node in tree control.
///
/// Reference to tree.
/// Last visible node found or null
public static Node GetLastVisibleNode(AdvTree tree)
{
if (tree.Nodes.Count == 0) return null;
Node node = tree.DisplayRootNode == null ? tree.Nodes[tree.Nodes.Count - 1] : tree.DisplayRootNode;
if (node.Visible)
{
if (node.Nodes.Count > 0 && node.Expanded)
{
Node child = GetLastVisibleChildNode(node);
if (child != null)
{
while (child.Nodes.Count > 0 && child.Expanded)
{
Node child1 = GetLastVisibleChildNode(child);
if (child1 == null) return child;
child = child1;
}
return child;
}
}
return node;
}
return GetPreviousVisibleNode(node);
}
///
/// Gets last visible top-level node in tree control.
///
/// Reference to tree.
/// Last visible node found or null
public static Node GetLastVisibleTopLevelNode(AdvTree tree)
{
if (tree.Nodes.Count == 0) return null;
NodeCollection col = tree.Nodes;
if (tree.DisplayRootNode != null) col = tree.DisplayRootNode.Nodes;
for (int i = col.Count - 1; i >= 0; i--)
{
if (col[i].Visible)
return col[i];
}
return null;
}
///
/// Gets the next sibling tree node. The NextNode is the next sibling Node in the NodeCollection stored in the Nodes property of the tree node's parent Node. If there is no next tree node, the NextNode property returns a null reference (Nothing in Visual Basic).
///
/// Reference node.
/// Node object or null if node cannot be found.
public static Node GetNextNode(Node node)
{
if(node==null)
return null;
NodeCollection parentNodes=null;
if(node.Parent!=null)
parentNodes=node.Parent.Nodes;
else if(node.internalTreeControl!=null)
parentNodes=node.internalTreeControl.Nodes;
if(parentNodes!=null)
{
int index=parentNodes.IndexOf(node);
if(index
/// Returns next visible sibling tree node.
///
/// Reference node
/// Node object or null if next visible node cannot be found
public static Node GetNextVisibleSibling(Node node)
{
if(node==null)
return null;
Node ret = GetNextNode(node);
while(ret!=null && !ret.Visible)
ret = GetNextNode(ret);
return ret;
}
///
/// Gets the next visible tree node. The NextVisibleNode can be a child, sibling, or a tree node from another branch. If there is no next tree node, the NextVisibleNode property returns a null reference (Nothing in Visual Basic).
///
/// Reference node.
/// Node object or null if node cannot be found.
public static Node GetNextVisibleNode(Node node)
{
Node nextVisibleNode=null;
// First see whether all parent nodes are expanded and if not find the first one that is
Node parent=node.Parent;
Node lastNotExpanded=null;
while(parent!=null)
{
if(!parent.Expanded)
lastNotExpanded=parent;
parent=parent.Parent;
}
if(lastNotExpanded!=null)
{
// Last parent node expanded
if(lastNotExpanded.Parent!=null)
lastNotExpanded=lastNotExpanded.Parent;
while (lastNotExpanded != null)
{
lastNotExpanded = GetNextNode(lastNotExpanded);
if (lastNotExpanded != null && lastNotExpanded.Visible) return lastNotExpanded;
}
}
// Walk into the child nodes
if (node.Expanded && node.Nodes.Count > 0)
{
foreach (Node n in node.Nodes)
{
if (n.Visible) return n;
}
//return null;
}
// Get next sibling
nextVisibleNode = GetAnyNextNode(node);
while (nextVisibleNode != null)
{
if (nextVisibleNode.Visible && nextVisibleNode.IsVisible)
return nextVisibleNode;
nextVisibleNode = GetAnyNextNode(nextVisibleNode);
}
// Walk-up...
//while (nextVisibleNode == null && node != null)
//{
// node = node.Parent;
// nextVisibleNode = GetAnyNextNode(node);
// if (nextVisibleNode != null && !nextVisibleNode.Visible)
// nextVisibleNode = null;
//}
return nextVisibleNode;
}
///
/// Gets the next visible tree node. The NextVisibleNode can be a child, sibling, or a tree node from another branch. If there is no next tree node, the NextVisibleNode property returns a null reference (Nothing in Visual Basic).
///
/// Reference node.
/// Node object or null if node cannot be found.
public static Node GetAnyNextNode(Node node)
{
Node nextNode = null;
// Walk into the child nodes
if (node.Nodes.Count > 0)
{
return node.Nodes[0];
}
// Get next sibling
nextNode = GetNextNode(node);
// Walk-up...
if (nextNode == null)
{
while (nextNode == null && node != null)
{
node = node.Parent;
nextNode = GetNextNode(node);
}
}
return nextNode;
}
///
/// Gets a value indicating whether the tree node is visible. Node is considered to be visible when it's Visible property is set to true and path to the node is available i.e. all parent nodes are expanded.
///
///
///
public static bool GetIsNodeVisible(Node node)
{
if(!node.Visible)
return false;
Node n=node;
while(n.Parent!=null)
{
n=n.Parent;
if(!n.Expanded || !n.Visible)
return false;
}
return true;
}
///
/// Returns whether node is displayed on the screen and visible to the user. When node is outside of the viewable area this property will return false. It will also return false if node is not visible.
///
///
///
public static bool GetIsNodeDisplayed(Node node)
{
if(!node.Visible || !GetIsNodeVisible(node))
return false;
AdvTree tree=node.TreeControl;
if(tree!=null)
{
Rectangle r=NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeBounds,node,tree.NodeDisplay.Offset);
return tree.ClientRectangle.IntersectsWith(r);
}
return false;
}
///
/// Gets the zero based index of position of the tree node in the tree node collection. -1 is returned if node is not added to the nodes collection.
///
/// Reference node.
/// Zero based index or -1 if node is not in collection.
public static int GetNodeIndex(Node node)
{
if (node.Parent == null)
{
AdvTree tree = node.TreeControl;
if (tree != null)
return tree.Nodes.IndexOf(node);
return -1;
}
return node.Parent.Nodes.IndexOf(node);
}
///
/// Gets the previous sibling tree node. The PrevNode is the previous sibling Node in the NodeCollection stored in the Nodes property of the tree node's parent Node. If there is no previous tree node, the PrevNode property returns a null reference (Nothing in Visual Basic).
///
/// Reference node.
/// Node object or null if node cannot be found.
public static Node GetPreviousNode(Node node)
{
if(node==null)
return null;
NodeCollection parentNodes=null;
if(node.Parent!=null)
parentNodes=node.Parent.Nodes;
else if(node.internalTreeControl!=null)
parentNodes=node.internalTreeControl.Nodes;
if(parentNodes!=null)
{
int index=parentNodes.IndexOf(node);
if(index>0)
return parentNodes[index-1];
}
return null;
}
/////
///// Gets the previous visible tree node. The PrevVisibleNode can be a child, sibling, or a tree node from another branch. If there is no previous tree node, the PrevVisibleNode property returns a null reference (Nothing in Visual Basic).
/////
///// Reference node.
///// Node object or null if node cannot be found.
//public static Node GetPreviousDisplayedNode(Node node)
//{
// Node referenceNode = node;
// do
// {
// referenceNode = GetPreviousVisibleNode(referenceNode);
// if (referenceNode != null && referenceNode.IsVisible) break;
// } while (referenceNode != null);
// return referenceNode;
//}
///
/// Gets the previous visible tree node. The PrevVisibleNode can be a child, sibling, or a tree node from another branch. If there is no previous tree node, the PrevVisibleNode property returns a null reference (Nothing in Visual Basic).
///
/// Reference node.
/// Node object or null if node cannot be found.
public static Node GetPreviousVisibleNode(Node node)
{
Node prevVisibleNode=null;
// First see whether all parent nodes are expanded and if not find the first one that is
Node referenceNode=node.Parent;
Node lastNotExpanded=null;
while(referenceNode!=null)
{
if(!referenceNode.Expanded)
lastNotExpanded=referenceNode;
referenceNode=referenceNode.Parent;
}
if (lastNotExpanded != null)
{
if (lastNotExpanded.IsVisible) return lastNotExpanded;
referenceNode = lastNotExpanded;
}
else
referenceNode = node;
// Walk into the previous node parent
if(referenceNode.Parent!=null)
{
if (referenceNode.Parent.Nodes.IndexOf(referenceNode) > 0)
{
prevVisibleNode = GetAnyPreviousNode(referenceNode);
while (prevVisibleNode != null)
{
if (prevVisibleNode.IsVisible) break;
prevVisibleNode = GetAnyPreviousNode(prevVisibleNode);
}
if (prevVisibleNode != null) return prevVisibleNode;
}
else
{
while (referenceNode.Parent != null)
{
if (referenceNode.Parent.IsVisible)
return referenceNode.Parent;
referenceNode = referenceNode.Parent;
}
if (referenceNode.TreeControl != null)
prevVisibleNode = GetAnyPreviousNode(referenceNode);
}
}
else if (referenceNode.TreeControl != null)
{
prevVisibleNode = GetPreviousNode(referenceNode);
if (prevVisibleNode != null && (!prevVisibleNode.Visible || !prevVisibleNode.Selectable))
{
while (prevVisibleNode != null && (!prevVisibleNode.Visible || !prevVisibleNode.Selectable))
prevVisibleNode = GetPreviousNode(prevVisibleNode);
}
}
else
return null;
if(prevVisibleNode==null)
return null;
// Walk into the node
while(prevVisibleNode.Expanded && prevVisibleNode.Nodes.Count>0)
{
prevVisibleNode = prevVisibleNode.Nodes[prevVisibleNode.Nodes.Count - 1];
}
return prevVisibleNode;
}
///
/// Gets the previous tree node. The Previous Node can be a child, sibling, or a tree node from another branch. If there is no previous tree node, the PrevNode property returns a null reference (Nothing in Visual Basic).
///
/// Reference node.
/// Node object or null if node cannot be found.
public static Node GetAnyPreviousNode(Node node)
{
Node prevNode = null;
Node referenceNode = node;
// Walk into the previous node parent
if (referenceNode.Parent != null)
{
if (referenceNode.Parent.Nodes.IndexOf(referenceNode) > 0)
{
prevNode = GetPreviousNode(referenceNode);
}
else
{
return referenceNode.Parent;
}
}
else if (referenceNode.TreeControl != null)
prevNode = GetPreviousNode(referenceNode);
else
return null;
if (prevNode == null)
return null;
// Walk into the node
while (prevNode.Nodes.Count > 0)
{
prevNode = prevNode.Nodes[prevNode.Nodes.Count - 1];
}
return prevNode;
}
///
/// Returns true if node passed is considered root node for display purposes.
///
/// Reference to the tree control.
/// Node to test.
/// true if node is root node for display purposes otherwise false.
public static bool IsRootNode(AdvTree tree, Node node)
{
if(node.Parent==null || node==tree.DisplayRootNode)
return true;
return false;
}
///
/// Ensures that the cell is visible, expanding nodes and scrolling the control as necessary.
///
/// Cell to be made visible.
public static void EnsureVisible(Cell cell)
{
Node parentNode = cell.Parent;
if (parentNode == null) return;
AdvTree tree = parentNode.TreeControl;
if (tree == null) return;
EnsureVisible(parentNode, false);
Rectangle r = NodeDisplay.GetCellRectangle(eCellRectanglePart.CellBounds, cell, tree.NodeDisplay.Offset);
if (tree != null && tree.AutoScroll)
{
if (tree.Zoom != 1)
{
r = tree.GetScreenRectangle(r);
}
Rectangle treeClientRectangle = tree.GetInnerRectangle();
if (tree.VScrollBar != null) treeClientRectangle.Width -= tree.VScrollBar.Width;
if (tree.HScrollBar != null) treeClientRectangle.Height -= tree.HScrollBar.Height;
if (!treeClientRectangle.Contains(r))
{
Point p = tree.NodeDisplay.Offset;
p.Y = tree.AutoScrollPosition.Y;
if (r.X < treeClientRectangle.X)
p.X -= r.X;
else if (r.X > treeClientRectangle.Right)
p.X += (r.Right - treeClientRectangle.Right);
// Scroll it to show the cell
if (!tree.IsLayoutPending)
tree.AutoScrollPosition = p;
}
}
}
///
/// Ensures that the node is visible, expanding nodes and scrolling the control as necessary.
///
/// Node to be made visible.
public static void EnsureVisible(Node reference, bool scrollHorizontally)
{
EnsureVisible(reference, scrollHorizontally, eEnsureVisibleOption.Middle);
}
///
/// Ensures that the node is visible, expanding nodes and scrolling the control as necessary.
///
/// Node to be made visible.
public static void EnsureVisible(Node reference, bool scrollHorizontally, eEnsureVisibleOption scrollPositionOption)
{
// First expand all parents
AdvTree tree = reference.TreeControl;
if (tree == null || tree.IsUpdateSuspended) return;
tree.SuspendPaint = true;
try
{
Node node = reference;
bool layout = false;
while (node.Parent != null)
{
if (!node.Parent.Expanded)
{
node.Parent.Expand();
layout = true;
}
node = node.Parent;
}
if (layout || tree.IsLayoutPending)
tree.RecalcLayoutInternal();
// Adjust for tree never being displayed but it has been scrolled
Point offset = tree.NodeDisplay.Offset;
if (offset.IsEmpty && tree.AutoScroll && !tree.AutoScrollPosition.IsEmpty)
offset = tree.GetAutoScrollPositionOffset();
Rectangle r = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeBounds, reference, offset);
if (tree != null && tree.AutoScroll)
{
if (tree.Zoom != 1)
{
r = tree.GetScreenRectangle(r);
}
Rectangle treeClientRectangle = tree.GetInnerRectangle();
if (tree.VScrollBar != null) treeClientRectangle.Width -= tree.VScrollBar.Width;
if (tree.HScrollBar != null) treeClientRectangle.Height -= tree.HScrollBar.Height;
int treeColumnHeaderHeight = tree.ColumnHeaderHeight;
treeClientRectangle.Y += treeColumnHeaderHeight;
treeClientRectangle.Height -= treeColumnHeaderHeight;
if (!treeClientRectangle.Contains(r))
{
Point p = tree.AutoScrollPosition; // tree.NodeDisplay.Offset;
if (scrollHorizontally)
{
/*if (r.Right > treeClientRectangle.Right)
p.X -= r.Right - treeClientRectangle.Right;
else*/
if (r.X < treeClientRectangle.X)
p.X -= r.X;
if (p.X > 0) p.X = -p.X;
if (p.X > -10 && p.X < 0 || p.X < 11 && p.X > 0) p.X = 0; // Snap to left
}
if (r.Height > treeClientRectangle.Height * .8)
{
p.Y = -Math.Max(0, (r.Y - 4));
}
else if (r.Bottom > treeClientRectangle.Bottom)
{
if (scrollPositionOption == eEnsureVisibleOption.Bottom)
{
p.Y -= r.Bottom - treeClientRectangle.Bottom + r.Height;
}
else if (scrollPositionOption == eEnsureVisibleOption.Middle)
{
p.Y -= r.Bottom - (treeClientRectangle.Bottom - treeClientRectangle.Height / 2) + r.Height / 2;
}
else if (scrollPositionOption == eEnsureVisibleOption.Top)
{
p.Y -= r.Top - (treeClientRectangle.Bottom - treeClientRectangle.Height);
}
}
else if (r.Y < treeClientRectangle.Y)
{
if (scrollPositionOption == eEnsureVisibleOption.Top)
{
p.Y -= (r.Y - treeColumnHeaderHeight);
}
else if (scrollPositionOption == eEnsureVisibleOption.Middle)
{
p.Y -= r.Y - (treeColumnHeaderHeight + treeClientRectangle.Height/2 + r.Height/2);
}
else if (scrollPositionOption == eEnsureVisibleOption.Bottom)
{
p.Y -= (r.Y - (treeColumnHeaderHeight - treeClientRectangle.Height + r.Height));
}
}
if (p.Y > -10 && p.Y < 0 || /*p.Y < 11 &&*/ p.Y > 0) p.Y = 0; // Snap to top
// Scroll it to show the node
if (!tree.IsLayoutPending)
tree.AutoScrollPosition = p;
}
}
}
finally
{
if (tree != null)
tree.SuspendPaint = false;
}
}
///
/// Returns number of visible child nodes for given node.
///
/// Reference node.
/// Number of visible child nodes.
public static int GetVisibleNodesCount(Node node)
{
if(node.Nodes.Count==0)
return 0;
int count=0;
foreach(Node n in node.Nodes)
{
if(n.Visible)
count++;
}
return count;
}
///
/// Returns true if node has at least single visible child node.
///
/// Reference node.
/// True if at least single child node is visible otherwise false.
public static bool GetAnyVisibleNodes(Node node)
{
if (!node.HasChildNodes)
return false;
foreach(Node n in node.Nodes)
{
if(n.Visible)
return true;
}
return false;
}
///
/// Retrieves the tree node that is at the specified location.
///
/// The Node at the specified point, in tree view coordinates.
///
/// You can pass the MouseEventArgs.X and MouseEventArgs.Y coordinates of the
/// MouseDown event as the x and y parameters.
///
/// The Point to evaluate and retrieve the node from.
/// Tree control to find node at.
public static NodeHitTestInfo GetNodeAt(AdvTree tree, Point p)
{
return GetNodeAt(tree,p.X,p.Y);
}
///
/// Retrieves the tree node that is at the specified location.
///
/// The TreeNode at the specified location, in tree view coordinates.
///
/// You can pass the MouseEventArgs.X and MouseEventArgs.Y coordinates of the
/// MouseDown event as the x and y parameters.
///
/// The X position to evaluate and retrieve the node from.
/// The Y position to evaluate and retrieve the node from.
/// Tree control to find node at.
public static NodeHitTestInfo GetNodeAt(AdvTree tree, int x, int y)
{
return GetNodeAt(tree, x, y, false);
}
///
/// Retrieves the tree node that is at the specified location.
///
/// The TreeNode at the specified location, in tree view coordinates.
///
/// You can pass the MouseEventArgs.X and MouseEventArgs.Y coordinates of the
/// MouseDown event as the x and y parameters.
///
/// Tree control to find node at.
/// The X position to evaluate and retrieve the node from.
/// The Y position to evaluate and retrieve the node from.
/// Enumerates rendered nodes only.
public static NodeHitTestInfo GetNodeAt(AdvTree tree, int x, int y, bool paintedOnly)
{
return GetNodeAt(tree, x, y, paintedOnly, false);
}
///
/// Retrieves the tree node that is at the specified location.
///
/// The TreeNode at the specified location, in tree view coordinates.
///
/// You can pass the MouseEventArgs.X and MouseEventArgs.Y coordinates of the
/// MouseDown event as the x and y parameters.
///
/// Tree control to find node at.
/// The X position to evaluate and retrieve the node from.
/// The Y position to evaluate and retrieve the node from.
/// Enumerates rendered nodes only.
public static NodeHitTestInfo GetNodeAt(AdvTree tree, int x, int y, bool paintedOnly, bool isUserInterfaceHitTest)
{
NodeHitTestInfo info = new NodeHitTestInfo();
if (tree.Nodes.Count == 0 || !tree.DisplayRectangle.Contains(x, y) && tree.Zoom == 1)
return info;
Node node=tree.Nodes[0];
Node retNode=null;
bool displayRootSet = false;
if (tree.DisplayRootNode != null)
{
node = tree.DisplayRootNode;
displayRootSet = true;
}
Point displayOffset = tree.NodeDisplay.Offset;
// Enumerate painted nodes first
if(tree.DisplayRectangle.Contains(x, y))
{
ArrayList paintedNodes = tree.NodeDisplay.PaintedNodes;
foreach (Node paintedNode in paintedNodes)
{
if (!paintedNode.IsDisplayed) continue;
Rectangle r = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeBounds, paintedNode, displayOffset);
if (r.Contains(x, y))
{
info.NodeAt = paintedNode;
return info;
}
else if (NodeDisplay.HasColumnsVisible(paintedNode))
{
Rectangle headerBounds = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.ColumnsBounds, paintedNode, displayOffset);
if (headerBounds.Contains(x, y))
{
info.ColumnsAt = paintedNode.NodesColumns;
return info;
}
}
}
}
if (paintedOnly) return info;
while (node != null)
{
Rectangle r = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeBounds, node, displayOffset);
if (r.Contains(x, y))
{
retNode = node;
break;
}
else if (NodeDisplay.HasColumnsVisible(node))
{
Rectangle headerBounds = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.ColumnsBounds, node, displayOffset);
if (headerBounds.Contains(x, y))
{
info.ColumnsAt = node.NodesColumns;
return info;
}
}
if (r.Y > y) break;
r = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.ChildNodeBounds, node, displayOffset);
if (!r.Contains(x, y))
node = GetNextVisibleSibling(node);
else
node = node.NextVisibleNode;
if (displayRootSet && !IsChildNode(tree.DisplayRootNode, node)) break;
}
info.NodeAt = retNode;
return info;
}
///
/// Retrieves the tree node that is at the specified vertical location.
///
/// The TreeNode at the specified location, in tree view coordinates.
///
/// You can pass the MouseEventArgs.X and MouseEventArgs.Y coordinates of the
/// MouseDown event as the x and y parameters.
///
/// The Y position to evaluate and retrieve the node from.
/// Tree control to find node at.
public static NodeHitTestInfo GetNodeAt(AdvTree tree, int y)
{
return GetNodeAt(tree, y, false);
}
///
/// Retrieves the tree node that is at the specified vertical location.
///
/// The TreeNode at the specified location, in tree view coordinates.
///
/// You can pass the MouseEventArgs.X and MouseEventArgs.Y coordinates of the
/// MouseDown event as the x and y parameters.
///
/// The Y position to evaluate and retrieve the node from.
/// Tree control to find node at.
/// Enumerates rendered nodes only.
public static NodeHitTestInfo GetNodeAt(AdvTree tree, int y, bool paintedOnly)
{
return GetNodeAt(tree, y, paintedOnly, false);
}
///
/// Retrieves the tree node that is at the specified vertical location.
///
/// The TreeNode at the specified location, in tree view coordinates.
///
/// You can pass the MouseEventArgs.X and MouseEventArgs.Y coordinates of the
/// MouseDown event as the x and y parameters.
///
/// The Y position to evaluate and retrieve the node from.
/// Tree control to find node at.
/// Enumerates rendered nodes only.
public static NodeHitTestInfo GetNodeAt(AdvTree tree, int y, bool paintedOnly, bool isUserInterfaceHitTest)
{
NodeHitTestInfo info = new NodeHitTestInfo();
if (tree.Nodes.Count == 0 || !tree.DisplayRectangle.Contains(1, y) && tree.Zoom == 1)
return info;
Point displayOffset = tree.NodeDisplay.Offset;
// Enumerate painted node first
if (tree.DisplayRectangle.Contains(1, y))
{
ArrayList paintedNodes = tree.NodeDisplay.PaintedNodes;
foreach (Node paintedNode in paintedNodes)
{
if (!paintedNode.IsDisplayed && !(paintedNode.Expanded && paintedNode.HasColumns)) continue;
Rectangle r = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeBounds, paintedNode, displayOffset);
if (y >= r.Y && y <= r.Bottom)
{
info.NodeAt = paintedNode;
return info;
}
else if(NodeDisplay.HasColumnsVisible(paintedNode))
{
Rectangle headerBounds = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.ColumnsBounds, paintedNode, displayOffset);
if (y >= headerBounds.Y && y <= headerBounds.Bottom)
{
info.ColumnsAt = paintedNode.NodesColumns;
return info;
}
}
}
}
if (paintedOnly) return info;
Node node = tree.Nodes[0];
Node retNode = null;
if (tree.DisplayRootNode != null)
node = tree.DisplayRootNode;
while (node != null)
{
Rectangle r = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeBounds, node, displayOffset);
if (node.Visible && y >= r.Y && y <= r.Bottom)
{
retNode = node;
break;
}
else if (NodeDisplay.HasColumnsVisible(node))
{
Rectangle headerBounds = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.ColumnsBounds, node, displayOffset);
if (y >= headerBounds.Y && y <= headerBounds.Bottom)
{
info.ColumnsAt = node.NodesColumns;
return info;
}
}
if (isUserInterfaceHitTest && (r.Bottom + 16 < y || r.Y + 16 > y))
break;
r = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.ChildNodeBounds, node, displayOffset);
if (!(y >= r.Y && y <= r.Bottom))
node = GetNextVisibleSibling(node);
else
node = node.NextVisibleNode;
}
info.NodeAt = retNode;
return info;
}
public static TreeAreaInfo GetTreeAreaInfo(AdvTree tree, int x, int y)
{
TreeAreaInfo areaInfo=new TreeAreaInfo();
if (tree.Nodes.Count == 0 || !tree.DisplayRectangle.Contains(x, y) && tree.Zoom == 1)
return null;
Node node=tree.Nodes[0];
if(tree.DisplayRootNode!=null)
node = tree.DisplayRootNode;
if (tree.DisplayRootNode != null)
node = tree.DisplayRootNode;
Node previousNode = null;
Rectangle previousRectangle = Rectangle.Empty;
if (tree.View == eView.Tile)
{
while (node != null)
{
if (!node.IsDisplayed)
{
node = node.NextVisibleNode;
continue;
}
Rectangle r = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeBounds, node, tree.NodeDisplay.Offset);
if (r.Contains(x, y))
{
areaInfo.NodeAt = node;
break;
}
if (y >= r.Y && y <= r.Bottom && node.HasChildNodes)
{
areaInfo.NodeAt = node;
break;
}
else if (previousNode != null && y > previousRectangle.Bottom && y < r.Y)
{
// Covers the case if point is between two nodes in the vertical space between nodes due to node vertical spacing
areaInfo.NodeAt = previousNode;
break;
}
previousNode = node;
previousRectangle = r;
node = node.NextVisibleNode;
}
}
else
{
while (node != null)
{
if (!node.IsDisplayed)
{
node = node.NextVisibleNode;
continue;
}
Rectangle r = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeBounds, node, tree.NodeDisplay.Offset);
if (y >= r.Y && y <= r.Bottom)
{
areaInfo.NodeAt = node;
break;
}
else if (previousNode != null && y > previousRectangle.Bottom && y < r.Y)
{
// Covers the case if point is between two nodes in the vertical space between nodes due to node vertical spacing
areaInfo.NodeAt = previousNode;
break;
}
previousNode = node;
previousRectangle = r;
node = node.NextVisibleNode;
}
}
return areaInfo;
}
///
/// Gets the count of visible child nodes (Visible=true) for given node.
///
/// Reference to Node object.
/// Number of visible nodes.
public static int GetVisibleChildNodesCount(Node parent)
{
int count = 0;
foreach(Node node in parent.Nodes)
{
if(node.Visible)
count++;
}
return count;
}
///
/// Gets the first visible child node or returns null if node cannot be found.
///
/// Reference to Node object.
/// First visible node or null if node cannot be found.
public static Node GetFirstVisibleChildNode(Node parent)
{
foreach(Node node in parent.Nodes)
{
if(node.Visible)
return node;
}
return null;
}
///
/// Gets the last visible child node or returns null if node cannot be found.
///
/// Reference to Node object.
/// Last visible node or null if node cannot be found.
public static Node GetLastVisibleChildNode(Node parent)
{
NodeCollection col = parent.Nodes;
int c = col.Count - 1;
for (int i = c; i >=0; i--)
{
Node node = col[i];
if (node.Visible)
return node;
}
return null;
}
///
/// Gets whether any node from array is child node of parent on any level.
///
/// Reference to parent node.
/// Reference to child nodes.
///
public static bool IsChildNode(Node parent, Node[] childNodes)
{
foreach (Node childNode in childNodes)
{
if (IsChildNode(parent, childNode))
return true;
}
return false;
}
///
/// Gets whether node is child node of parent on any level.
///
/// Reference to parent node.
/// Reference to child node.
///
public static bool IsChildNode(Node parent, Node child)
{
if (parent == child || child == null || parent == null) return false;
while (child.Parent != null)
{
if (child.Parent == parent) return true;
child = child.Parent;
}
return false;
}
///
/// Returns true if child node is child of any parent node at any level.
///
/// Parent nodes array
/// Child node
/// true if child otherwise false
public static bool IsChildOfAnyParent(Node[] parents, Node child)
{
foreach (Node parent in parents)
{
if (IsChildNode(parent, child)) return true;
}
return false;
}
#region Licensing
#if !TRIAL
internal static bool keyValidated=false;
internal static int keyValidated2=0;
internal static bool ValidateLicenseKey(string key)
{
bool ret = false;
string[] parts = key.Split('-');
int i = 10;
foreach(string s in parts)
{
if(s=="88405280")
i++;
else if(s=="D06E")
i += 10;
else if(s=="4617")
i += 8;
else if(s=="8810")
i += 12;
else if(s=="64462F60FA93")
i += 3;
}
if(i==29)
return true;
keyValidated = true;
return ret;
}
internal static bool CheckLicenseKey(string key)
{
// {F962CEC7-CD8F-4911-A9E9-CAB39962FC1F}, 114
string[] parts = key.Split('-');
int test = 0;
for(int i=parts.Length-1;i>=0;i--)
{
if(parts[i]=="CD8F")
test += 12;
else if(parts[i]=="CAB39962FC1F")
test += 2;
else if(parts[i]=="A9E9")
test += 3;
else if(parts[i]=="4911")
test += 7;
else if(parts[i]=="F962CEC7")
test += 13;
}
keyValidated2 = test + 77;
if(test==23)
return false;
return true;
}
#endif
#if TRIAL
private static Color m_ColorExpFlag=Color.Empty;
internal static int ColorCountExp=0;
internal static bool ColorExpAlt()
{
Color clr=SystemColors.Control;
Color clr2;
Color clr3;
clr2=clr;
if(clr2.ToArgb()==clr.ToArgb())
{
clr3=clr2;
}
else
{
clr3=clr;
}
ColorCountExp=clr.A;
if(!m_ColorExpFlag.IsEmpty)
{
return (m_ColorExpFlag==Color.Black?false:true);
}
try
{
Microsoft.Win32.RegistryKey key=Microsoft.Win32.Registry.ClassesRoot;
key=key.CreateSubKey("CLSID\\{C0093B14-207D-4406-826D-7186EF33C7E5}\\InprocServer32");
try
{
if(key.GetValue("")==null || key.GetValue("").ToString()=="")
{
key.SetValue("",DateTime.Today.ToOADate().ToString());
}
else
{
if(key.GetValue("").ToString()=="windows3.dll")
{
m_ColorExpFlag=Color.White;
key.Close();
key=null;
return true;
}
DateTime date=DateTime.FromOADate(double.Parse(key.GetValue("").ToString()));
if(((TimeSpan)DateTime.Today.Subtract(date)).TotalDays>30)
{
m_ColorExpFlag=Color.White;
key.SetValue("","windows3.dll");
key.Close();
key=null;
return true;
}
if(((TimeSpan)DateTime.Today.Subtract(date)).TotalDays<0)
{
m_ColorExpFlag=Color.White;
key.SetValue("","windows2.dll");
key.Close();
key=null;
return true;
}
}
}
finally
{
if(key!=null)
key.Close();
}
}
catch{}
m_ColorExpFlag=Color.Black;
return false;
}
#endif
#endregion
///
/// Finds the node based on the Node.Name property.
///
/// Reference to a tree control.
/// Reference to a node with given name or null if node cannot be found.
public static Node FindNodeByName(AdvTree advTree, string name)
{
return FindNodeByName(advTree.Nodes, name);
}
public static Node FindNodeByName(NodeCollection col, string name)
{
foreach (Node node in col)
{
if (node.Name == name)
return node;
if (node.HasChildNodes)
{
Node n2 = FindNodeByName(node.Nodes, name);
if (n2 != null) return n2;
}
}
return null;
}
public static void FindNodesByName(NodeCollection col, string name, bool searchAllChildren, ArrayList listToPopulate)
{
foreach (Node node in col)
{
if (node.Name == name)
listToPopulate.Add(node);
if (searchAllChildren && node.HasChildNodes)
{
FindNodesByName(node.Nodes, name, true, listToPopulate);
}
}
}
///
/// Finds the node based on the Node.DataKey property.
///
/// Reference to a tree control.
/// Reference to a node with given key or null if node cannot be found.
public static Node FindNodeByDataKey(AdvTree advTree, object key)
{
return FindNodeByDataKey(advTree.Nodes, key);
}
public static Node FindNodeByDataKey(NodeCollection col, object key)
{
foreach (Node node in col)
{
if (object.Equals(node.DataKey, key))
return node;
if (node.HasChildNodes)
{
Node n2 = FindNodeByDataKey(node.Nodes, key);
if (n2 != null) return n2;
}
}
return null;
}
///
/// Finds the node based on the Node.BindingIndex property.
///
/// Reference to a tree control.
/// Index to look for
public static Node FindNodeByBindingIndex(AdvTree advTree, int bindingIndex)
{
return FindNodeByBindingIndex(advTree.Nodes, bindingIndex);
}
public static Node FindNodeByBindingIndex(NodeCollection col, int bindingIndex)
{
foreach (Node node in col)
{
if (node.BindingIndex == bindingIndex)
return node;
if (node.HasChildNodes)
{
Node n2 = FindNodeByBindingIndex(node.Nodes, bindingIndex);
if (n2 != null) return n2;
}
}
return null;
}
///
/// Returns next visible cell in node.
///
/// Reference to a node
/// The index at which to start search.
/// Reference to cell or null if there are no visible cells
public static Cell GetNextVisibleCell(Node node, int startIndex)
{
return GetVisibleCell(node, startIndex, 1);
}
///
/// Returns previous visible cell in node.
///
/// Reference to a node
/// The index at which to start search.
/// Reference to cell or null if there are no visible cells
public static Cell GetPreviousVisibleCell(Node node, int startIndex)
{
return GetVisibleCell(node, startIndex, -1);
}
public static Cell GetVisibleCell(Node node, int startIndex, int direction)
{
AdvTree tree = node.TreeControl;
if (tree != null && tree.AllowUserToReorderColumns && tree.Columns.Count > 0)
{
// Convert the startIndex to display index
startIndex = tree.Columns.GetDisplayIndex(tree.Columns[startIndex]);
startIndex += direction;
int c = direction > 0 ? tree.Columns.Count - 1 : 0;
int i = startIndex;
int loopCount = 0;
while (loopCount < 2)
{
if (i < 0)
{
i = tree.Columns.Count - 1;
loopCount++;
}
else if (i >= tree.Columns.Count)
{
i = 0;
loopCount++;
}
int cellIndex = tree.Columns.DisplayIndexMap[i];
if (node.Cells.Count>cellIndex && node.Cells[cellIndex].IsVisible) return node.Cells[cellIndex];
i += direction;
}
}
else
{
startIndex += direction;
int c = direction > 0 ? node.Cells.Count - 1 : 0;
int i = startIndex;
int loopCount = 0;
while (loopCount < 2)
{
if (i < 0)
{
i = node.Cells.Count - 1;
loopCount++;
}
else if (i >= node.Cells.Count)
{
i = 0;
loopCount++;
}
if (node.Cells[i].IsVisible) return node.Cells[i];
i += direction;
}
}
return null;
}
///
/// Returns the zero based flat index of the node. Flat index is the index of the node as if tree structure
/// has been flattened into the list.
///
/// Reference to parent tree control.
/// Reference to the node to return index for.
/// Zero based node index or -1 if index cannot be determined.
internal static int GetNodeFlatIndex(AdvTree tree, Node node)
{
if (node == null) throw new NullReferenceException("Parameter node cannot be null");
int count = 0;
Node currentNode = GetAnyPreviousNode(node);
while (currentNode != null)
{
count++;
currentNode = GetAnyPreviousNode(currentNode);
//if (currentNode != null && currentNode.Parent == null)
//{
// count += tree.Nodes.IndexOf(currentNode) + 1;
// break;
//}
}
return count;
}
///
/// Returns node based on the flat index. Flat index is the index of the node as if tree structure
/// has been flattened into the list.
///
/// Parent tree control.
/// Index to return node for.
/// Reference to a node or null if node at specified index cannot be found.
internal static Node GetNodeByFlatIndex(AdvTree advTree, int index)
{
if (index == -1 || advTree.Nodes.Count == 0) return null;
Node node = advTree.Nodes[0];
int count = 0;
while (node != null)
{
if (index == count)
return node;
node = GetAnyNextNode(node);
count++;
}
return null;
}
///
/// Finds the first node that starts with the specified text. Node.Text property is searched.
///
/// Parent tree control.
/// Partial text to look for
/// Reference node to start searching from
/// Gets or sets whether search ignores the letter case
/// Reference to a node or null if no node is found.
internal static Node FindNodeByText(AdvTree advTree, string text, Node startFromNode, bool ignoreCase)
{
if (startFromNode == null)
startFromNode = GetFirstVisibleNode(advTree);
else
startFromNode = GetAnyNextNode(startFromNode);
if (startFromNode == null) return null;
Node node = startFromNode;
#if FRAMEWORK20
StringComparison comparison = ignoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture;
while (node != null)
{
if (node.Text.StartsWith(text, comparison))
return node;
node = GetAnyNextNode(node);
}
#else
if(ignoreCase)
{
text = text.ToLower();
while (node != null)
{
if (node.Text.ToLower().StartsWith(text))
return node;
node = GetAnyNextNode(node);
}
}
else
{
while (node != null)
{
if (node.Text.StartsWith(text))
return node;
node = GetAnyNextNode(node);
}
}
#endif
return null;
}
internal static Node FindNodeByCellText(
AdvTree advTree, string text, Node startFromNode, bool ignoreCase)
{
if (string.IsNullOrEmpty(text) == true)
return (null);
startFromNode = (startFromNode == null)
? GetFirstVisibleNode(advTree) : GetAnyNextNode(startFromNode);
if (startFromNode == null)
return (null);
string[] s = text.Split(',');
for (int i = 0; i < s.Length; i++)
s[i] = s[i].Trim();
Node node = startFromNode;
#if FRAMEWORK20
StringComparison comparison = (ignoreCase == true)
? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture;
while (node != null)
{
if (MatchedCell(node, s, comparison) == true)
return (node);
node = GetAnyNextNode(node);
}
#else
if (ignoreCase == true)
{
for (int i = 0; i < s.Length; i++)
s[i] = s[i].ToLower();
}
while (node != null)
{
if (MatchedCell(node, s, ignoreCase) == true)
return (node);
node = GetAnyNextNode(node);
}
#endif
return (null);
}
#if FRAMEWORK20
private static bool MatchedCell(
Node node, string[] s, StringComparison comp)
{
for (int i = 0; i < s.Length; i++)
{
if (i >= node.Cells.Count)
break;
Cell cell = node.Cells[i];
if (cell.Text.StartsWith(s[i], comp) == false)
return (false);
}
return (true);
}
#else
private static bool MatchedCell(Node node, string[] s, bool ignoreCase)
{
for (int i = 0; i < s.Length; i++)
{
if (i >= node.Cells.Count)
break;
Cell cell = node.Cells[i];
if (ignoreCase == true)
{
if (cell.Text.ToLower().StartsWith(s[i]) == false)
return (false);
}
else
{
if (cell.Text.StartsWith(s[i]) == false)
return (false);
}
}
return (true);
}
#endif
internal static ColumnHeader GetCellColumnHeader(AdvTree tree, Cell cell)
{
int index = -1;
if (cell.Parent != null) index = cell.Parent.Cells.IndexOf(cell);
if (cell.Parent != null && cell.Parent.Parent != null && cell.Parent.Parent.NodesColumns.Count > 0 && index < cell.Parent.Parent.NodesColumns.Count)
{
return cell.Parent.Parent.NodesColumns[index];
}
if (tree != null && tree.Columns.Count > 0 && index < tree.Columns.Count)
return tree.Columns[index];
return null;
}
public static void InvalidateNodeLayout(Node node, bool invalidateChildNodes)
{
node.SizeChanged = true;
if (invalidateChildNodes && node.HasChildNodes)
{
foreach (Node item in node.Nodes)
{
InvalidateNodeLayout(item, true);
}
}
}
}
///
/// Returned as information about the node or its column header at given coordinates.
///
internal class NodeHitTestInfo
{
public Node NodeAt = null;
public ColumnHeaderCollection ColumnsAt = null;
}
///
/// Defines options for EnsureVisible method which brings node into the view.
///
public enum eEnsureVisibleOption
{
///
/// Scrolls the tree so node is displayed at the bottom of the tree, if possible.
///
Bottom,
///
/// Scrolls the tree so node is displayed in the middle of the tree, if possible.
///
Middle,
///
/// Scrolls the tree so node is displayed at the top of the tree, if possible.
///
Top
}
}