/* 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
{
///
/// This interface is used to hide these members from general use.
///
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;
}
///
/// 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.
///
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;
}
}
}
}
///
/// 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.
///
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;
}
}
}
}
///
/// Gets the internal prop bag for this node. Users of this property should always check for null after calling this property.
///
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;
}
///
/// Gets a value indicating whether the tree node is in the selected state.
///
///
/// true if the tree node is in the selected state; otherwise, false.
///
public new bool IsSelected
{
get
{
return _selected;
}
}
///
/// 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.
///
public bool ShowCheckBox
{
get
{
return _showCheckBox;
}
set
{
if (_showCheckBox != value)
{
_showCheckBox = value;
if (TreeView != null)
{
TreeView.UpdateCheckboxVisibility(this);
}
}
}
}
///
/// Iterates through all the descendants of this .
///
public IEnumerable Descendants
{
get
{
foreach (MultiSelectTreeNode node in Nodes)
{
yield return node;
foreach (MultiSelectTreeNode n in node.Descendants)
{
yield return n;
}
}
}
}
///
/// Gets the parent tree view that the tree node is assigned to.
///
///
///
/// A 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.
///
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
}
}