mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-12-22 16:36:03 +01:00
7c0bc50b4a
Inc. Signed-off-by: Gabor Apati-Nagy<gabor.apati-nagy@citrix.com>
939 lines
30 KiB
C#
939 lines
30 KiB
C#
/* Copyright (c) Citrix Systems, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms,
|
|
* with or without modification, are permitted provided
|
|
* that the following conditions are met:
|
|
*
|
|
* * Redistributions of source code must retain the above
|
|
* copyright notice, this list of conditions and the
|
|
* following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the
|
|
* following disclaimer in the documentation and/or other
|
|
* materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
using System.Collections.Generic;
|
|
using System.Windows.Forms;
|
|
using System.ComponentModel;
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Diagnostics;
|
|
using System.Collections.ObjectModel;
|
|
|
|
namespace XenAdmin.Controls
|
|
{
|
|
/// <summary>
|
|
/// A <see cref="TreeView"/> that only adds <see cref="TreeNode"/>s when they become visible.
|
|
/// </summary>
|
|
public partial class VirtualTreeView : MultiSelectTreeView, IVirtualTreeNodeCollectionOwner, IHaveNodes
|
|
{
|
|
private readonly VirtualTreeNodeCollection _nodes;
|
|
private readonly VirtualTreeSelectedNodeCollection _selectedNodes;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="VirtualTreeView"/> class.
|
|
/// </summary>
|
|
public VirtualTreeView()
|
|
{
|
|
_nodes = new VirtualTreeNodeCollection(this);
|
|
_selectedNodes = new VirtualTreeSelectedNodeCollection(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the tree node that is currently selected in the tree view control.
|
|
/// </summary>
|
|
/// <value></value>
|
|
/// <returns>
|
|
/// The <see cref="VirtualTreeNode"/> that is currently selected in the tree view control.
|
|
/// </returns>
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
[Browsable(false)]
|
|
public new VirtualTreeNode SelectedNode
|
|
{
|
|
get
|
|
{
|
|
return (VirtualTreeNode)base.SelectedNode;
|
|
}
|
|
set
|
|
{
|
|
if (value != null)
|
|
{
|
|
Devirtualise(value);
|
|
}
|
|
base.SelectedNode = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the first fully-visible tree node in the tree view control.
|
|
/// </summary>
|
|
/// <value></value>
|
|
/// <returns>
|
|
/// A <see cref="VirtualTreeNode"/> that represents the first fully-visible tree node in the tree view control.
|
|
/// </returns>
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
[Browsable(false)]
|
|
public new VirtualTreeNode TopNode
|
|
{
|
|
get { return (VirtualTreeNode)base.TopNode; }
|
|
set
|
|
{
|
|
Util.ThrowIfParameterNull(value, "value");
|
|
Devirtualise(value);
|
|
base.TopNode = value;
|
|
}
|
|
}
|
|
|
|
private static List<VirtualTreeNode> GetParents(VirtualTreeNode node)
|
|
{
|
|
List<VirtualTreeNode> parents = new List<VirtualTreeNode>();
|
|
|
|
VirtualTreeNode nn = node.Parent;
|
|
while (nn != null)
|
|
{
|
|
parents.Add(nn);
|
|
nn = nn.Parent;
|
|
}
|
|
parents.Reverse();
|
|
return parents;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Populates the real nodes for every node from the root down to this node.
|
|
/// </summary>
|
|
private void Devirtualise(VirtualTreeNode node)
|
|
{
|
|
foreach (VirtualTreeNode parent in GetParents(node))
|
|
{
|
|
Devirtualise(parent.Nodes);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ensures that all real nodes are up-to-date with the virtual ones.
|
|
/// </summary>
|
|
private void Devirtualise(VirtualTreeNodeCollection nodes)
|
|
{
|
|
if (NodeCollectionRequiresUpdate(nodes.Owner))
|
|
{
|
|
nodes.Owner.RealNodes.Clear();
|
|
nodes.Owner.RealNodes.AddRange(new List<VirtualTreeNode>(nodes).ToArray());
|
|
}
|
|
}
|
|
|
|
private static bool NodeCollectionRequiresUpdate(IVirtualTreeNodeCollectionOwner owner)
|
|
{
|
|
if (owner.RealNodes.Count == 1 && owner.RealNodes[0] is DummyTreeNode)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (owner.RealNodes.Count != owner.Nodes.Count)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
for (int i = 0; i < owner.Nodes.Count; i++)
|
|
{
|
|
if (owner.RealNodes[i] != owner.Nodes[i])
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public new VirtualTreeSelectedNodeCollection SelectedNodes
|
|
{
|
|
get { return _selectedNodes; }
|
|
}
|
|
|
|
#region IVirtualTreeNodeCollectionOwner Members
|
|
|
|
public new VirtualTreeNodeCollection Nodes
|
|
{
|
|
get { return _nodes; }
|
|
}
|
|
|
|
MultiSelectTreeNodeCollection IVirtualTreeNodeCollectionOwner.RealNodes
|
|
{
|
|
get { return base.Nodes; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IHaveNodes Members
|
|
|
|
VirtualTreeView.VirtualTreeNodeCollection IHaveNodes.Nodes
|
|
{
|
|
get { return Nodes; }
|
|
}
|
|
|
|
object IHaveNodes.Tag
|
|
{
|
|
get { return Tag; }
|
|
}
|
|
|
|
void IHaveNodes.Expand()
|
|
{
|
|
}
|
|
|
|
void IHaveNodes.Collapse()
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Retrieves the tree node that is at the specified point.
|
|
/// </summary>
|
|
public new VirtualTreeNode GetNodeAt(Point pt)
|
|
{
|
|
return (VirtualTreeNode)base.GetNodeAt(pt);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the tree node that is at the specified point.
|
|
/// </summary>
|
|
public new VirtualTreeNode GetNodeAt(int x, int y)
|
|
{
|
|
return (VirtualTreeNode)base.GetNodeAt(x, y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Merges the specified node tree with the existing one. Automatically does a BeginUpdate
|
|
/// if the nodes change.
|
|
/// </summary>
|
|
/// <param name="newRootNodes">The new root nodes.</param>
|
|
public void UpdateRootNodes(IEnumerable<VirtualTreeNode> newRootNodes)
|
|
{
|
|
Util.ThrowIfParameterNull(newRootNodes, "newRootNodes");
|
|
|
|
foreach (VirtualTreeNode node in newRootNodes)
|
|
{
|
|
if (node.TreeView != null)
|
|
{
|
|
throw new ArgumentException("newRootNodes should not be attached to a TreeView.", "newRootNodes");
|
|
}
|
|
}
|
|
|
|
bool doneBeginUpdate = false;
|
|
UpdateNodes(Nodes, new List<VirtualTreeNode>(newRootNodes), ref doneBeginUpdate);
|
|
}
|
|
|
|
private void UpdateNodes(VirtualTreeNodeCollection oldNodes, IList<VirtualTreeNode> newNodes, ref bool doneBeginUpdate)
|
|
{
|
|
for (int i = 0; i < Math.Max(oldNodes.Count, newNodes.Count); )
|
|
{
|
|
if (oldNodes.Count > i && newNodes.Count > i)
|
|
{
|
|
if (oldNodes[i].Nodes.Count > 0 && newNodes[i].Nodes.Count == 0 && oldNodes[i].IsExpanded)
|
|
{
|
|
// fix for issues CA-34486 and CA-36409
|
|
// see VirtualTreeViewTests.TestUpdateWhenRemoveAllChildNodesOfExandedParent
|
|
|
|
// When merging sets of tree-nodes using UpdateRootNodes, if you remove all of
|
|
// the child-nodes from a node, the node still remembers its IsExpanded state
|
|
// from before the nodes were removed regardless of whether you call Collapse()
|
|
// or Expand() after the nodes were removed.
|
|
|
|
// This causes problems for the Virtual treeview as it
|
|
// relies the BeforeExpanded event to convert DummyTreeNodes into VirtualTreeNodes
|
|
// on population.
|
|
|
|
oldNodes[i].Collapse();
|
|
}
|
|
|
|
UpdateNode(newNodes[i], oldNodes[i], ref doneBeginUpdate);
|
|
UpdateNodes(oldNodes[i].Nodes, newNodes[i].Nodes, ref doneBeginUpdate);
|
|
i++;
|
|
}
|
|
else if (oldNodes.Count <= i && newNodes.Count > i)
|
|
{
|
|
LogTreeView("Adding node " + newNodes[i].Text);
|
|
DoBeginUpdateIfRequired(ref doneBeginUpdate);
|
|
oldNodes.Add(newNodes[i]);
|
|
UpdateNodes(oldNodes[i].Nodes, newNodes[i].Nodes, ref doneBeginUpdate);
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
LogTreeView("Removing node " + oldNodes[i].Text);
|
|
DoBeginUpdateIfRequired(ref doneBeginUpdate);
|
|
oldNodes.RemoveAt(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DoBeginUpdateIfRequired(ref bool doneBeginUpdate)
|
|
{
|
|
if (!doneBeginUpdate)
|
|
{
|
|
doneBeginUpdate = true;
|
|
BeginUpdate();
|
|
}
|
|
}
|
|
|
|
[Conditional("DEBUG")]
|
|
private void LogTreeView(string s)
|
|
{
|
|
//Debug.WriteLine(s);
|
|
}
|
|
|
|
private void UpdateNode(VirtualTreeNode src, VirtualTreeNode dest, ref bool doneBeginUpdate)
|
|
{
|
|
if (dest.ImageIndex != src.ImageIndex)
|
|
{
|
|
DoBeginUpdateIfRequired(ref doneBeginUpdate);
|
|
dest.ImageIndex = src.ImageIndex;
|
|
}
|
|
|
|
if (dest.SelectedImageIndex != src.SelectedImageIndex)
|
|
{
|
|
DoBeginUpdateIfRequired(ref doneBeginUpdate);
|
|
dest.SelectedImageIndex = src.SelectedImageIndex;
|
|
}
|
|
|
|
if (dest.Text != src.Text)
|
|
{
|
|
LogTreeView("Overwriting " + src.Text + " with " + dest.Text);
|
|
DoBeginUpdateIfRequired(ref doneBeginUpdate);
|
|
dest.Text = src.Text;
|
|
}
|
|
|
|
if (dest.Tag != src.Tag)
|
|
{
|
|
dest.Tag = src.Tag;
|
|
}
|
|
|
|
if (dest.NodeFont != src.NodeFont)
|
|
{
|
|
DoBeginUpdateIfRequired(ref doneBeginUpdate);
|
|
dest.NodeFont = src.NodeFont;
|
|
}
|
|
|
|
if (dest.BackColor != src.BackColor)
|
|
{
|
|
DoBeginUpdateIfRequired(ref doneBeginUpdate);
|
|
dest.BackColor = src.BackColor;
|
|
}
|
|
|
|
if (dest.ForeColor != src.ForeColor)
|
|
{
|
|
DoBeginUpdateIfRequired(ref doneBeginUpdate);
|
|
dest.ForeColor = src.ForeColor;
|
|
}
|
|
|
|
if (dest.Name != src.Name)
|
|
{
|
|
DoBeginUpdateIfRequired(ref doneBeginUpdate);
|
|
dest.Name = src.Name;
|
|
}
|
|
|
|
if (dest.ShowCheckBox != src.ShowCheckBox)
|
|
{
|
|
DoBeginUpdateIfRequired(ref doneBeginUpdate);
|
|
dest.ShowCheckBox = src.ShowCheckBox;
|
|
}
|
|
|
|
if (dest.Checked != src.Checked)
|
|
{
|
|
DoBeginUpdateIfRequired(ref doneBeginUpdate);
|
|
dest.Checked = src.Checked;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Iterates through every node of this <see cref="VirtualTreeView"/>.
|
|
/// </summary>
|
|
public new IEnumerable<VirtualTreeNode> AllNodes
|
|
{
|
|
get
|
|
{
|
|
foreach (VirtualTreeNode node in Nodes)
|
|
{
|
|
yield return node;
|
|
|
|
foreach (VirtualTreeNode n in node.Descendants)
|
|
{
|
|
yield return n;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region Virtual overrides
|
|
|
|
protected sealed override void OnAfterCheck(TreeViewEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
OnAfterCheck(new VirtualTreeViewEventArgs(node, e.Action));
|
|
}
|
|
|
|
protected sealed override void OnBeforeCheck(TreeViewCancelEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
VirtualTreeViewCancelEventArgs args = new VirtualTreeViewCancelEventArgs(node, e.Cancel, e.Action);
|
|
OnBeforeCheck(args);
|
|
e.Cancel = args.Cancel;
|
|
}
|
|
|
|
protected sealed override void OnAfterCollapse(TreeViewEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
OnAfterCollapse(new VirtualTreeViewEventArgs(node, e.Action));
|
|
}
|
|
|
|
protected sealed override void OnBeforeCollapse(TreeViewCancelEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
VirtualTreeViewCancelEventArgs args = new VirtualTreeViewCancelEventArgs(node, e.Cancel, e.Action);
|
|
OnBeforeCollapse(args);
|
|
e.Cancel = args.Cancel;
|
|
}
|
|
|
|
protected sealed override void OnAfterExpand(TreeViewEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
OnAfterExpand(new VirtualTreeViewEventArgs(node, e.Action));
|
|
}
|
|
|
|
protected sealed override void OnBeforeExpand(TreeViewCancelEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
Devirtualise(node.Nodes);
|
|
VirtualTreeViewCancelEventArgs args = new VirtualTreeViewCancelEventArgs(node, e.Cancel, e.Action);
|
|
OnBeforeExpand(args);
|
|
e.Cancel = args.Cancel;
|
|
}
|
|
|
|
protected sealed override void OnAfterDeselect(TreeViewEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
OnAfterDeselect(new VirtualTreeViewEventArgs(node));
|
|
}
|
|
|
|
protected sealed override void OnBeforeDeselect(TreeViewEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
OnBeforeDeselect(new VirtualTreeViewEventArgs(node));
|
|
}
|
|
|
|
protected sealed override void OnAfterSelect(TreeViewEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
OnAfterSelect(new VirtualTreeViewEventArgs(node, e.Action));
|
|
}
|
|
|
|
protected sealed override void OnBeforeSelect(MultiSelectTreeViewCancelEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
VirtualTreeViewCancelEventArgs args = new VirtualTreeViewCancelEventArgs(node, e.Cancel, e.Action);
|
|
OnBeforeSelect(args);
|
|
e.Cancel = args.Cancel;
|
|
}
|
|
|
|
protected sealed override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
OnNodeMouseClick(new VirtualTreeNodeMouseClickEventArgs(node, e.Button, e.Clicks, e.X, e.Y));
|
|
}
|
|
|
|
protected sealed override void OnNodeMouseDoubleClick(TreeNodeMouseClickEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
OnNodeMouseDoubleClick(new VirtualTreeNodeMouseClickEventArgs(node, e.Button, e.Clicks, e.X, e.Y));
|
|
}
|
|
|
|
protected sealed override void OnAfterLabelEdit(NodeLabelEditEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
VirtualNodeLabelEditEventArgs args = new VirtualNodeLabelEditEventArgs(node, e.Label);
|
|
OnAfterLabelEdit(args);
|
|
e.CancelEdit = args.CancelEdit;
|
|
}
|
|
|
|
protected sealed override void OnBeforeLabelEdit(NodeLabelEditEventArgs e)
|
|
{
|
|
VirtualTreeNode node = (VirtualTreeNode)e.Node;
|
|
VirtualNodeLabelEditEventArgs args = new VirtualNodeLabelEditEventArgs(node, e.Label);
|
|
OnBeforeLabelEdit(args);
|
|
e.CancelEdit = args.CancelEdit;
|
|
}
|
|
|
|
protected sealed override void OnItemDrag(MultiSelectTreeViewItemDragEventArgs e)
|
|
{
|
|
List<VirtualTreeNode> nodes = new List<VirtualTreeNode>();
|
|
|
|
foreach (MultiSelectTreeNode n in e.Nodes)
|
|
{
|
|
nodes.Add((VirtualTreeNode)n);
|
|
}
|
|
|
|
OnItemDrag(new VirtualTreeViewItemDragEventArgs(e.Button, nodes));
|
|
}
|
|
|
|
protected virtual void OnAfterCheck(VirtualTreeViewEventArgs e)
|
|
{
|
|
EventHandler<VirtualTreeViewEventArgs> handler = AfterCheck;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnBeforeCheck(VirtualTreeViewCancelEventArgs e)
|
|
{
|
|
EventHandler<VirtualTreeViewCancelEventArgs> handler = BeforeCheck;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnAfterCollapse(VirtualTreeViewEventArgs e)
|
|
{
|
|
EventHandler<VirtualTreeViewEventArgs> handler = AfterCollapse;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnBeforeCollapse(VirtualTreeViewCancelEventArgs e)
|
|
{
|
|
EventHandler<VirtualTreeViewCancelEventArgs> handler = BeforeCollapse;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnAfterExpand(VirtualTreeViewEventArgs e)
|
|
{
|
|
EventHandler<VirtualTreeViewEventArgs> handler = AfterExpand;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnBeforeExpand(VirtualTreeViewCancelEventArgs e)
|
|
{
|
|
EventHandler<VirtualTreeViewCancelEventArgs> handler = BeforeExpand;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnAfterDeselect(VirtualTreeViewEventArgs e)
|
|
{
|
|
EventHandler<VirtualTreeViewEventArgs> handler = AfterDeselect;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnBeforeDeselect(VirtualTreeViewEventArgs e)
|
|
{
|
|
EventHandler<VirtualTreeViewEventArgs> handler = BeforeDeselect;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnAfterSelect(VirtualTreeViewEventArgs e)
|
|
{
|
|
EventHandler<VirtualTreeViewEventArgs> handler = AfterSelect;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnBeforeSelect(VirtualTreeViewCancelEventArgs e)
|
|
{
|
|
EventHandler<VirtualTreeViewCancelEventArgs> handler = BeforeSelect;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnBeforeLabelEdit(VirtualNodeLabelEditEventArgs e)
|
|
{
|
|
EventHandler<VirtualNodeLabelEditEventArgs> handler = BeforeLabelEdit;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnAfterLabelEdit(VirtualNodeLabelEditEventArgs e)
|
|
{
|
|
EventHandler<VirtualNodeLabelEditEventArgs> handler = AfterLabelEdit;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
|
|
protected virtual void OnNodeMouseClick(VirtualTreeNodeMouseClickEventArgs e)
|
|
{
|
|
EventHandler<VirtualTreeNodeMouseClickEventArgs> handler = NodeMouseClick;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnNodeMouseDoubleClick(VirtualTreeNodeMouseClickEventArgs e)
|
|
{
|
|
EventHandler<VirtualTreeNodeMouseClickEventArgs> handler = NodeMouseDoubleClick;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnItemDrag(VirtualTreeViewItemDragEventArgs e)
|
|
{
|
|
EventHandler<VirtualTreeViewItemDragEventArgs> handler = ItemDrag;
|
|
|
|
if (handler != null)
|
|
{
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Events
|
|
|
|
/// <summary>
|
|
/// Occurs after the tree node check box is checked.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs after the tree node check box is checked.")]
|
|
public new event EventHandler<VirtualTreeViewEventArgs> AfterCheck;
|
|
|
|
/// <summary>
|
|
/// Occurs before the tree node check box is checked.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs before the tree node check box is checked.")]
|
|
public new event EventHandler<VirtualTreeViewCancelEventArgs> BeforeCheck;
|
|
|
|
/// <summary>
|
|
/// Occurs after the tree node is collapsed.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs after the tree node is collapsed.")]
|
|
public new event EventHandler<VirtualTreeViewEventArgs> AfterCollapse;
|
|
|
|
/// <summary>
|
|
/// Occurs before the tree node is collapsed.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs before the tree node is collapsed.")]
|
|
public new event EventHandler<VirtualTreeViewCancelEventArgs> BeforeCollapse;
|
|
|
|
/// <summary>
|
|
/// Occurs after the tree node is expanded.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs after the tree node is expanded.")]
|
|
public new event EventHandler<VirtualTreeViewEventArgs> AfterExpand;
|
|
|
|
/// <summary>
|
|
/// Occurs before the tree node is expanded.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs after the tree node is expanded.")]
|
|
public new event EventHandler<VirtualTreeViewCancelEventArgs> BeforeExpand;
|
|
|
|
/// <summary>
|
|
/// Occurs after the tree node is deselected.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs after the tree node is deselected.")]
|
|
public new event EventHandler<VirtualTreeViewEventArgs> AfterDeselect;
|
|
|
|
/// <summary>
|
|
/// Occurs before the tree node is deselected.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs after the tree node is deselected.")]
|
|
public new event EventHandler<VirtualTreeViewEventArgs> BeforeDeselect;
|
|
|
|
/// <summary>
|
|
/// Occurs after the tree node is selected.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs after the tree node is selected.")]
|
|
public new event EventHandler<VirtualTreeViewEventArgs> AfterSelect;
|
|
|
|
/// <summary>
|
|
/// Occurs before the tree node is selected.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs before the tree node is selected.")]
|
|
public new event EventHandler<VirtualTreeViewCancelEventArgs> BeforeSelect;
|
|
|
|
/// <summary>
|
|
/// Occurs after the node is clicked.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs after the node is clicked.")]
|
|
public new event EventHandler<VirtualTreeNodeMouseClickEventArgs> NodeMouseClick;
|
|
|
|
/// <summary>
|
|
/// Occurs after the node is double clicked.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs after the node is double clicked.")]
|
|
public new event EventHandler<VirtualTreeNodeMouseClickEventArgs> NodeMouseDoubleClick;
|
|
|
|
/// <summary>
|
|
/// Occurs after the tree node label is edited.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs after the tree node label is edited.")]
|
|
public new event EventHandler<VirtualNodeLabelEditEventArgs> AfterLabelEdit;
|
|
|
|
/// <summary>
|
|
/// Occurs before the tree node label is edited.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs before the tree node label is edited.")]
|
|
public new event EventHandler<VirtualNodeLabelEditEventArgs> BeforeLabelEdit;
|
|
|
|
/// <summary>
|
|
/// Occurs when a node starts being dragged.
|
|
/// </summary>
|
|
[Category("Behavior"), Description("Occurs when a node starts being dragged.")]
|
|
public new event EventHandler<VirtualTreeViewItemDragEventArgs> ItemDrag;
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Used to ensure that the '+' expander thingy is visible when a node has children.
|
|
/// </summary>
|
|
private class DummyTreeNode : MultiSelectTreeNode
|
|
{
|
|
}
|
|
}
|
|
|
|
internal interface IVirtualTreeNodeCollectionOwner
|
|
{
|
|
/// <summary>
|
|
/// Gets a complete collection of nodes owned.
|
|
/// </summary>
|
|
VirtualTreeView.VirtualTreeNodeCollection Nodes { get;}
|
|
|
|
/// <summary>
|
|
/// Gets a collection of the nodes which are actually added to the base <see cref="System.Windows.Forms.TreeView"/>.
|
|
/// </summary>
|
|
MultiSelectTreeNodeCollection RealNodes { get;}
|
|
}
|
|
|
|
internal interface IHaveNodes
|
|
{
|
|
VirtualTreeView.VirtualTreeNodeCollection Nodes { get; }
|
|
object Tag { get; }
|
|
void Expand();
|
|
void Collapse();
|
|
}
|
|
|
|
#region VirtualTreeView EventArgs classes
|
|
|
|
public class VirtualTreeViewEventArgs : EventArgs
|
|
{
|
|
private readonly TreeViewAction _action;
|
|
private readonly VirtualTreeNode _node;
|
|
|
|
public VirtualTreeViewEventArgs(VirtualTreeNode node)
|
|
{
|
|
Util.ThrowIfParameterNull(node, "node");
|
|
|
|
_node = node;
|
|
}
|
|
|
|
public VirtualTreeViewEventArgs(VirtualTreeNode node, TreeViewAction action)
|
|
: this(node)
|
|
{
|
|
_action = action;
|
|
}
|
|
|
|
public TreeViewAction Action
|
|
{
|
|
get
|
|
{
|
|
return _action;
|
|
}
|
|
}
|
|
|
|
public VirtualTreeNode Node
|
|
{
|
|
get
|
|
{
|
|
return _node;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class VirtualTreeViewCancelEventArgs : CancelEventArgs
|
|
{
|
|
private readonly TreeViewAction _action;
|
|
private readonly VirtualTreeNode _node;
|
|
|
|
public VirtualTreeViewCancelEventArgs(VirtualTreeNode node, bool cancel, TreeViewAction action)
|
|
: base(cancel)
|
|
{
|
|
_node = node;
|
|
_action = action;
|
|
}
|
|
|
|
public TreeViewAction Action
|
|
{
|
|
get
|
|
{
|
|
return _action;
|
|
}
|
|
}
|
|
|
|
public VirtualTreeNode Node
|
|
{
|
|
get
|
|
{
|
|
return _node;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class VirtualTreeNodeMouseClickEventArgs : MouseEventArgs
|
|
{
|
|
private readonly VirtualTreeNode _node;
|
|
|
|
public VirtualTreeNodeMouseClickEventArgs(VirtualTreeNode node, MouseButtons button, int clicks, int x, int y)
|
|
: base(button , clicks , x , y, 0)
|
|
{
|
|
_node = node;
|
|
}
|
|
|
|
public VirtualTreeNode Node
|
|
{
|
|
get
|
|
{
|
|
return _node;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class VirtualNodeLabelEditEventArgs : EventArgs
|
|
{
|
|
private bool _cancelEdit;
|
|
private readonly string _label;
|
|
private readonly VirtualTreeNode _node;
|
|
|
|
public VirtualNodeLabelEditEventArgs(VirtualTreeNode node)
|
|
{
|
|
Util.ThrowIfParameterNull(node, "node");
|
|
|
|
_node = node;
|
|
_label = null;
|
|
}
|
|
|
|
public VirtualNodeLabelEditEventArgs(VirtualTreeNode node, string label)
|
|
: this(node)
|
|
{
|
|
_label = label;
|
|
}
|
|
|
|
public bool CancelEdit
|
|
{
|
|
get
|
|
{
|
|
return _cancelEdit;
|
|
}
|
|
set
|
|
{
|
|
_cancelEdit = value;
|
|
}
|
|
}
|
|
|
|
public string Label
|
|
{
|
|
get
|
|
{
|
|
return _label;
|
|
}
|
|
}
|
|
|
|
public VirtualTreeNode Node
|
|
{
|
|
get
|
|
{
|
|
return _node;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class VirtualTreeViewItemDragEventArgs : EventArgs
|
|
{
|
|
private readonly ReadOnlyCollection<VirtualTreeNode> _nodes;
|
|
private readonly MouseButtons _button;
|
|
|
|
public VirtualTreeViewItemDragEventArgs(MouseButtons button)
|
|
: this(button, new VirtualTreeNode[0])
|
|
{
|
|
}
|
|
|
|
public VirtualTreeViewItemDragEventArgs(MouseButtons button, IEnumerable<VirtualTreeNode> nodes)
|
|
{
|
|
_nodes = new ReadOnlyCollection<VirtualTreeNode>(new List<VirtualTreeNode>(nodes));
|
|
_button = button;
|
|
}
|
|
|
|
public MouseButtons Button
|
|
{
|
|
get
|
|
{
|
|
return _button;
|
|
}
|
|
}
|
|
|
|
public ReadOnlyCollection<VirtualTreeNode> Nodes
|
|
{
|
|
get
|
|
{
|
|
return _nodes;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|