mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-12-30 15:50:10 +01:00
362 lines
11 KiB
C#
362 lines
11 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;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Text;
|
|||
|
using System.Windows.Forms;
|
|||
|
using System.Drawing;
|
|||
|
using System.ComponentModel;
|
|||
|
using System.Reflection;
|
|||
|
|
|||
|
namespace XenAdmin.Controls
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// This interface is used to hide these members from general use.
|
|||
|
/// </summary>
|
|||
|
internal interface IMultiSelectTreeNode
|
|||
|
{
|
|||
|
void SetSelected(bool selected);
|
|||
|
void SetEnabled(bool enabled);
|
|||
|
}
|
|||
|
|
|||
|
public class MultiSelectTreeNode : TreeNode, IMultiSelectTreeNodeCollectionOwner, IMultiSelectTreeNode
|
|||
|
{
|
|||
|
private readonly MultiSelectTreeNodeCollection _nodes;
|
|||
|
private Color _backColor;
|
|||
|
private Color _foreColor;
|
|||
|
private bool _selected;
|
|||
|
private bool _enabled;
|
|||
|
private Color _highlightForeColor = SystemColors.HighlightText;
|
|||
|
private Color _highlightBackColor = SystemColors.Highlight;
|
|||
|
private bool _showCheckBox;
|
|||
|
|
|||
|
public MultiSelectTreeNode()
|
|||
|
: this(string.Empty)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
public MultiSelectTreeNode(string text)
|
|||
|
: base(text)
|
|||
|
{
|
|||
|
_nodes = new MultiSelectTreeNodeCollection(this);
|
|||
|
_backColor = BackColor;
|
|||
|
_foreColor = ForeColor;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets the back-color of the treeNode from the base class. If this is done by setting the BackColor of the base class, then
|
|||
|
/// the entire treeview is invalidated which can cause flicker. It is therefore achieved by setting the internal propbag and then invalidating
|
|||
|
/// just this node.
|
|||
|
/// </summary>
|
|||
|
private Color BaseBackColor
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return base.BackColor;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
if (value != base.BackColor)
|
|||
|
{
|
|||
|
if (TreeView != null && PropBag != null && TreeView.IsHandleCreated)
|
|||
|
{
|
|||
|
PropBag.BackColor = value;
|
|||
|
TreeView.Invalidate(Bounds);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
base.BackColor = value;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets the fore-color of the treeNode from the base class. If this is done by setting the BackColor of the base class, then
|
|||
|
/// the entire treeview is invalidated which can cause flicker. It is therefore achieved by setting the internal propbag and then invalidating
|
|||
|
/// just this node.
|
|||
|
/// </summary>
|
|||
|
private Color BaseForeColor
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return base.ForeColor;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
if (value != base.ForeColor)
|
|||
|
{
|
|||
|
if (TreeView != null && PropBag != null && TreeView.IsHandleCreated)
|
|||
|
{
|
|||
|
PropBag.ForeColor = value;
|
|||
|
TreeView.Invalidate(Bounds);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
base.ForeColor = value;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the internal prop bag for this node. Users of this property should always check for null after calling this property.
|
|||
|
/// </summary>
|
|||
|
private OwnerDrawPropertyBag PropBag
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
FieldInfo fieldInfo = GetType().GetField("propBag", BindingFlags.NonPublic | BindingFlags.Instance);
|
|||
|
|
|||
|
if (fieldInfo != null)
|
|||
|
{
|
|||
|
return (OwnerDrawPropertyBag)fieldInfo.GetValue(this);
|
|||
|
}
|
|||
|
|
|||
|
return null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void UpdateColors()
|
|||
|
{
|
|||
|
if (_enabled && _selected)
|
|||
|
{
|
|||
|
BaseBackColor = _highlightBackColor;
|
|||
|
BaseForeColor = _highlightForeColor;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
BaseBackColor = _backColor;
|
|||
|
BaseForeColor = _foreColor;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public new Color BackColor
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _backColor;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
_backColor = value;
|
|||
|
if (!_selected)
|
|||
|
{
|
|||
|
BaseBackColor = value;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public new Color ForeColor
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _foreColor;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
_foreColor = value;
|
|||
|
|
|||
|
if (!_selected)
|
|||
|
{
|
|||
|
BaseForeColor = value;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public Color HighlightForeColor
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _highlightForeColor;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
_highlightForeColor = value;
|
|||
|
UpdateColors();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public Color HighlightBackColor
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _highlightBackColor;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
_highlightBackColor = value;
|
|||
|
UpdateColors();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public new MultiSelectTreeNode NextVisibleNode
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return (MultiSelectTreeNode)base.NextVisibleNode;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public new MultiSelectTreeNode PrevVisibleNode
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return (MultiSelectTreeNode)base.PrevVisibleNode;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public new MultiSelectTreeNode Parent
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return (MultiSelectTreeNode)base.Parent;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private bool IsTreeViewEnabled()
|
|||
|
{
|
|||
|
// iterate through ancestors to find treeview as this node might have only just been
|
|||
|
// added and therefore the TreeView property will still return null.
|
|||
|
|
|||
|
MultiSelectTreeNode node = this;
|
|||
|
|
|||
|
while (node != null)
|
|||
|
{
|
|||
|
if (node.TreeView != null)
|
|||
|
{
|
|||
|
return node.TreeView.Enabled;
|
|||
|
}
|
|||
|
node = node.Parent;
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets a value indicating whether the tree node is in the selected state.
|
|||
|
/// </summary>
|
|||
|
/// <value></value>
|
|||
|
/// <returns>true if the tree node is in the selected state; otherwise, false.
|
|||
|
/// </returns>
|
|||
|
public new bool IsSelected
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _selected;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets a value indicating whether a CheckBox should be shown on this node. This
|
|||
|
/// only takes effect if TreeView.ShowCheckBoxes is set to true.
|
|||
|
/// </summary>
|
|||
|
public bool ShowCheckBox
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _showCheckBox;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
if (_showCheckBox != value)
|
|||
|
{
|
|||
|
_showCheckBox = value;
|
|||
|
if (TreeView != null)
|
|||
|
{
|
|||
|
TreeView.UpdateCheckboxVisibility(this);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Iterates through all the descendants of this <see cref="VirtualTreeNode"/>.
|
|||
|
/// </summary>
|
|||
|
public IEnumerable<MultiSelectTreeNode> Descendants
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
foreach (MultiSelectTreeNode node in Nodes)
|
|||
|
{
|
|||
|
yield return node;
|
|||
|
|
|||
|
foreach (MultiSelectTreeNode n in node.Descendants)
|
|||
|
{
|
|||
|
yield return n;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the parent tree view that the tree node is assigned to.
|
|||
|
/// </summary>
|
|||
|
/// <value></value>
|
|||
|
/// <returns>
|
|||
|
/// A <see cref="MultiSelectTreeView"/> that represents the parent tree view that the tree node is assigned to, or null if the node has not been assigned to a tree view.
|
|||
|
/// </returns>
|
|||
|
public new MultiSelectTreeView TreeView
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return (MultiSelectTreeView)base.TreeView;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#region IMultiSelectTreeNodeCollectionOwner Members
|
|||
|
|
|||
|
public new MultiSelectTreeNodeCollection Nodes
|
|||
|
{
|
|||
|
get { return _nodes; }
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region IMultiSelectTreeNode Members
|
|||
|
|
|||
|
void IMultiSelectTreeNode.SetSelected(bool selected)
|
|||
|
{
|
|||
|
_enabled = IsTreeViewEnabled();
|
|||
|
_selected = selected;
|
|||
|
UpdateColors();
|
|||
|
}
|
|||
|
|
|||
|
void IMultiSelectTreeNode.SetEnabled(bool enabled)
|
|||
|
{
|
|||
|
_enabled = enabled;
|
|||
|
UpdateColors();
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|