507 lines
11 KiB
C#
507 lines
11 KiB
C#
|
using System;
|
|||
|
using System.Windows.Forms;
|
|||
|
using System.Drawing;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Diagnostics;
|
|||
|
using System.ComponentModel;
|
|||
|
using System.ComponentModel.Design;
|
|||
|
using System.ComponentModel.Design.Serialization;
|
|||
|
using System.Drawing.Design;
|
|||
|
using System.Text;
|
|||
|
|
|||
|
namespace BismNormalizer.TabularCompare.UI
|
|||
|
{
|
|||
|
[
|
|||
|
ToolboxItem(false),
|
|||
|
DesignTimeVisible(false)
|
|||
|
]
|
|||
|
public class TreeGridNode : DataGridViewRow//, IComponent
|
|||
|
{
|
|||
|
internal TreeGridView _grid;
|
|||
|
internal TreeGridNode _parent;
|
|||
|
internal TreeGridNodeCollection _owner;
|
|||
|
internal bool IsExpanded;
|
|||
|
internal bool IsRoot;
|
|||
|
internal bool _isSited;
|
|||
|
internal bool _isFirstSibling;
|
|||
|
internal bool _isLastSibling;
|
|||
|
internal Image _image;
|
|||
|
internal int _imageIndex;
|
|||
|
|
|||
|
private Random rndSeed = new Random();
|
|||
|
public int UniqueValue = -1;
|
|||
|
TreeGridCell _treeCell;
|
|||
|
TreeGridNodeCollection childrenNodes;
|
|||
|
|
|||
|
private int _index;
|
|||
|
private int _level;
|
|||
|
private bool childCellsCreated = false;
|
|||
|
|
|||
|
// needed for IComponent
|
|||
|
private ISite site = null;
|
|||
|
private EventHandler disposed = null;
|
|||
|
|
|||
|
internal TreeGridNode(TreeGridView owner)
|
|||
|
: this()
|
|||
|
{
|
|||
|
this._grid = owner;
|
|||
|
this.IsExpanded = true;
|
|||
|
}
|
|||
|
|
|||
|
public TreeGridNode()
|
|||
|
{
|
|||
|
_index = -1;
|
|||
|
_level = -1;
|
|||
|
IsExpanded = false;
|
|||
|
UniqueValue = this.rndSeed.Next();
|
|||
|
_isSited = false;
|
|||
|
_isFirstSibling = false;
|
|||
|
_isLastSibling = false;
|
|||
|
_imageIndex = -1;
|
|||
|
}
|
|||
|
|
|||
|
public override object Clone()
|
|||
|
{
|
|||
|
TreeGridNode r = (TreeGridNode)base.Clone();
|
|||
|
r.UniqueValue = -1;
|
|||
|
r._level = this._level;
|
|||
|
r._grid = this._grid;
|
|||
|
r._parent = this.Parent;
|
|||
|
|
|||
|
r._imageIndex = this._imageIndex;
|
|||
|
if (r._imageIndex == -1)
|
|||
|
r.Image = this.Image;
|
|||
|
|
|||
|
r.IsExpanded = this.IsExpanded;
|
|||
|
//r.treeCell = new TreeGridCell();
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
internal protected virtual void UnSited()
|
|||
|
{
|
|||
|
// This row is being removed from being displayed on the grid.
|
|||
|
TreeGridCell cell;
|
|||
|
foreach (DataGridViewCell DGVcell in this.Cells)
|
|||
|
{
|
|||
|
cell = DGVcell as TreeGridCell;
|
|||
|
if (cell != null)
|
|||
|
{
|
|||
|
cell.UnSited();
|
|||
|
}
|
|||
|
}
|
|||
|
this._isSited = false;
|
|||
|
}
|
|||
|
|
|||
|
internal protected virtual void Sited()
|
|||
|
{
|
|||
|
// This row is being added to the grid.
|
|||
|
this._isSited = true;
|
|||
|
this.childCellsCreated = true;
|
|||
|
Debug.Assert(this._grid != null);
|
|||
|
|
|||
|
TreeGridCell cell;
|
|||
|
foreach (DataGridViewCell DGVcell in this.Cells)
|
|||
|
{
|
|||
|
cell = DGVcell as TreeGridCell;
|
|||
|
if (cell != null)
|
|||
|
{
|
|||
|
cell.Sited();// Level = this.Level;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// Represents the index of this row in the Grid
|
|||
|
[System.ComponentModel.Description("Represents the index of this row in the Grid. Advanced usage."),
|
|||
|
System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced),
|
|||
|
Browsable(false),
|
|||
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|||
|
public int RowIndex => base.Index;
|
|||
|
|
|||
|
// Represents the index of this row based upon its position in the collection.
|
|||
|
[Browsable(false),
|
|||
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|||
|
public new int Index
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (_index == -1)
|
|||
|
{
|
|||
|
// get the index from the collection if unknown
|
|||
|
_index = this._owner.IndexOf(this);
|
|||
|
}
|
|||
|
|
|||
|
return _index;
|
|||
|
}
|
|||
|
internal set
|
|||
|
{
|
|||
|
_index = value;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[Browsable(false),
|
|||
|
EditorBrowsable( EditorBrowsableState.Never),
|
|||
|
DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden)]
|
|||
|
public ImageList ImageList
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (this._grid != null)
|
|||
|
return this._grid.ImageList;
|
|||
|
else
|
|||
|
return null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private bool ShouldSerializeImageIndex() => (this._imageIndex != -1 && this._image == null);
|
|||
|
|
|||
|
[Category("Appearance"),
|
|||
|
Description("..."), DefaultValue(-1),
|
|||
|
TypeConverter(typeof(ImageIndexConverter)),
|
|||
|
Editor("System.Windows.Forms.Design.ImageIndexEditor", typeof(UITypeEditor))]
|
|||
|
public int ImageIndex
|
|||
|
{
|
|||
|
get { return _imageIndex; }
|
|||
|
set
|
|||
|
{
|
|||
|
_imageIndex = value;
|
|||
|
if (_imageIndex != -1)
|
|||
|
{
|
|||
|
// when a imageIndex is provided we do not store the image.
|
|||
|
this._image = null;
|
|||
|
}
|
|||
|
if (this._isSited)
|
|||
|
{
|
|||
|
// when the image changes the cell's style must be updated
|
|||
|
this._treeCell.UpdateStyle();
|
|||
|
if (this.Displayed)
|
|||
|
this._grid.InvalidateRow(this.RowIndex);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private bool ShouldSerializeImage() => (this._imageIndex == -1 && this._image != null);
|
|||
|
|
|||
|
public Image Image
|
|||
|
{
|
|||
|
get {
|
|||
|
if (_image == null && _imageIndex != -1)
|
|||
|
{
|
|||
|
if (this.ImageList != null && this._imageIndex < this.ImageList.Images.Count)
|
|||
|
{
|
|||
|
// get image from image index
|
|||
|
return this.ImageList.Images[this._imageIndex];
|
|||
|
}
|
|||
|
else
|
|||
|
return null;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// image from image property
|
|||
|
return this._image;
|
|||
|
};
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
_image = value;
|
|||
|
if (_image != null)
|
|||
|
{
|
|||
|
// when a image is provided we do not store the imageIndex.
|
|||
|
this._imageIndex = -1;
|
|||
|
}
|
|||
|
if (this._isSited)
|
|||
|
{
|
|||
|
// when the image changes the cell's style must be updated
|
|||
|
this._treeCell.UpdateStyle();
|
|||
|
if (this.Displayed)
|
|||
|
this._grid.InvalidateRow(this.RowIndex);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected override DataGridViewCellCollection CreateCellsInstance()
|
|||
|
{
|
|||
|
DataGridViewCellCollection cells = base.CreateCellsInstance();
|
|||
|
cells.CollectionChanged += cells_CollectionChanged;
|
|||
|
return cells;
|
|||
|
}
|
|||
|
|
|||
|
void cells_CollectionChanged(object sender, System.ComponentModel.CollectionChangeEventArgs e)
|
|||
|
{
|
|||
|
// Exit if there already is a tree cell for this row
|
|||
|
if (_treeCell != null) return;
|
|||
|
|
|||
|
if (e.Action == System.ComponentModel.CollectionChangeAction.Add || e.Action == System.ComponentModel.CollectionChangeAction.Refresh)
|
|||
|
{
|
|||
|
TreeGridCell treeCell = null;
|
|||
|
|
|||
|
if (e.Element == null)
|
|||
|
{
|
|||
|
foreach (DataGridViewCell cell in base.Cells)
|
|||
|
{
|
|||
|
if (cell.GetType().IsAssignableFrom(typeof(TreeGridCell)))
|
|||
|
{
|
|||
|
treeCell = (TreeGridCell)cell;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
treeCell = e.Element as TreeGridCell;
|
|||
|
}
|
|||
|
|
|||
|
if (treeCell != null)
|
|||
|
_treeCell = treeCell;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[Category("Data"),
|
|||
|
Description("The collection of root nodes in the treelist."),
|
|||
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] //,
|
|||
|
//Editor(typeof(CollectionEditor), typeof(UITypeEditor))]
|
|||
|
public TreeGridNodeCollection Nodes
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (childrenNodes == null)
|
|||
|
{
|
|||
|
childrenNodes = new TreeGridNodeCollection(this);
|
|||
|
}
|
|||
|
return childrenNodes;
|
|||
|
}
|
|||
|
set { ;}
|
|||
|
}
|
|||
|
|
|||
|
// Create a new Cell property because by default a row is not in the grid and won't
|
|||
|
// have any cells. We have to fabricate the cell collection ourself.
|
|||
|
[Browsable(false),
|
|||
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|||
|
public new DataGridViewCellCollection Cells
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (!childCellsCreated && this.DataGridView == null)
|
|||
|
{
|
|||
|
if (this._grid == null) return null;
|
|||
|
|
|||
|
this.CreateCells(this._grid);
|
|||
|
childCellsCreated = true;
|
|||
|
}
|
|||
|
return base.Cells;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[Browsable(false),
|
|||
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|||
|
public int Level
|
|||
|
{
|
|||
|
get {
|
|||
|
if (this._level == -1)
|
|||
|
{
|
|||
|
// calculate level
|
|||
|
int walk = 0;
|
|||
|
TreeGridNode walkRow = this.Parent;
|
|||
|
while (walkRow != null)
|
|||
|
{
|
|||
|
walk++;
|
|||
|
walkRow = walkRow.Parent;
|
|||
|
}
|
|||
|
this._level = walk;
|
|||
|
}
|
|||
|
return this._level; }
|
|||
|
}
|
|||
|
|
|||
|
[Browsable(false),
|
|||
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|||
|
public TreeGridNode Parent => this._parent;
|
|||
|
|
|||
|
[Browsable(false),
|
|||
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|||
|
public virtual bool HasChildren => (this.childrenNodes != null && this.Nodes.Count != 0);
|
|||
|
|
|||
|
[Browsable(false)]
|
|||
|
public bool IsSited => this._isSited;
|
|||
|
[Browsable(false)]
|
|||
|
public bool IsFirstSibling => (this.Index == 0);
|
|||
|
|
|||
|
[Browsable(false)]
|
|||
|
public bool IsLastSibling
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
TreeGridNode parent = this.Parent;
|
|||
|
if (parent != null && parent.HasChildren)
|
|||
|
{
|
|||
|
return (this.Index == parent.Nodes.Count - 1);
|
|||
|
}
|
|||
|
else
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public virtual bool Collapse() => this._grid.CollapseNode(this);
|
|||
|
|
|||
|
public virtual bool Expand()
|
|||
|
{
|
|||
|
if (this._grid != null)
|
|||
|
return this._grid.ExpandNode(this);
|
|||
|
else
|
|||
|
{
|
|||
|
this.IsExpanded = true;
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal protected virtual bool InsertChildNode(int index, TreeGridNode node)
|
|||
|
{
|
|||
|
node._parent = this;
|
|||
|
node._grid = this._grid;
|
|||
|
|
|||
|
// ensure that all children of this node has their grid set
|
|||
|
if (this._grid != null)
|
|||
|
UpdateChildNodes(node);
|
|||
|
|
|||
|
//TO_DO: do we need to use index parameter?
|
|||
|
if ((this._isSited || this.IsRoot) && this.IsExpanded)
|
|||
|
this._grid.SiteNode(node);
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
internal protected virtual bool InsertChildNodes(int index, params TreeGridNode[] nodes)
|
|||
|
{
|
|||
|
foreach (TreeGridNode node in nodes)
|
|||
|
{
|
|||
|
this.InsertChildNode(index, node);
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
internal protected virtual bool AddChildNode(TreeGridNode node)
|
|||
|
{
|
|||
|
node._parent = this;
|
|||
|
node._grid = this._grid;
|
|||
|
|
|||
|
// ensure that all children of this node has their grid set
|
|||
|
if (this._grid != null)
|
|||
|
UpdateChildNodes(node);
|
|||
|
|
|||
|
if ((this._isSited || this.IsRoot) && this.IsExpanded && !node._isSited)
|
|||
|
this._grid.SiteNode(node);
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
internal protected virtual bool AddChildNodes(params TreeGridNode[] nodes)
|
|||
|
{
|
|||
|
//TO_DO: Convert the final call into an SiteNodes??
|
|||
|
foreach (TreeGridNode node in nodes)
|
|||
|
{
|
|||
|
this.AddChildNode(node);
|
|||
|
}
|
|||
|
return true;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
internal protected virtual bool RemoveChildNode(TreeGridNode node)
|
|||
|
{
|
|||
|
if ((this.IsRoot || this._isSited) && this.IsExpanded )
|
|||
|
{
|
|||
|
//We only unsite out child node if we are sited and expanded.
|
|||
|
this._grid.UnSiteNode(node);
|
|||
|
|
|||
|
}
|
|||
|
node._grid = null;
|
|||
|
node._parent = null;
|
|||
|
return true;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
internal protected virtual bool ClearNodes()
|
|||
|
{
|
|||
|
if (this.HasChildren)
|
|||
|
{
|
|||
|
for (int i = this.Nodes.Count - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
this.Nodes.RemoveAt(i);
|
|||
|
}
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
[
|
|||
|
Browsable(false),
|
|||
|
EditorBrowsable(EditorBrowsableState.Advanced)
|
|||
|
]
|
|||
|
public event EventHandler Disposed
|
|||
|
{
|
|||
|
add
|
|||
|
{
|
|||
|
this.disposed += value;
|
|||
|
}
|
|||
|
remove
|
|||
|
{
|
|||
|
this.disposed -= value;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[
|
|||
|
Browsable(false),
|
|||
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
|
|||
|
]
|
|||
|
public ISite Site
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return this.site;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
this.site = value;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void UpdateChildNodes(TreeGridNode node)
|
|||
|
{
|
|||
|
if (node.HasChildren)
|
|||
|
{
|
|||
|
foreach (TreeGridNode childNode in node.Nodes)
|
|||
|
{
|
|||
|
childNode._grid = node._grid;
|
|||
|
this.UpdateChildNodes(childNode);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public override string ToString()
|
|||
|
{
|
|||
|
StringBuilder sb = new StringBuilder(36);
|
|||
|
sb.Append("TreeGridNode { Index=");
|
|||
|
sb.Append(this.RowIndex.ToString(System.Globalization.CultureInfo.CurrentCulture));
|
|||
|
sb.Append(" }");
|
|||
|
return sb.ToString();
|
|||
|
}
|
|||
|
|
|||
|
//protected override void Dispose(bool disposing) {
|
|||
|
// if (disposing)
|
|||
|
// {
|
|||
|
// lock(this)
|
|||
|
// {
|
|||
|
// if (this.site != null && this.site.Container != null)
|
|||
|
// {
|
|||
|
// this.site.Container.Remove(this);
|
|||
|
// }
|
|||
|
|
|||
|
// if (this.disposed != null)
|
|||
|
// {
|
|||
|
// this.disposed(this, EventArgs.Empty);
|
|||
|
// }
|
|||
|
// }
|
|||
|
// }
|
|||
|
|
|||
|
// base.Dispose(disposing);
|
|||
|
//}
|
|||
|
}
|
|||
|
|
|||
|
}
|