using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Collections.Generic;
using System.Windows.Forms;
namespace DevComponents.AdvTree
{
///
/// Represents collection for ColumnHeader objects.
///
public class ColumnHeaderCollection : CollectionBase
{
#region Private Variables
private Node _ParentNode = null;
private AdvTree _Parent = null;
#endregion
#region Internal Implementation
///
/// Default constructor.
///
public ColumnHeaderCollection()
{
}
///
/// Gets or sets the node this collection is associated with.
///
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Node ParentNode
{
get { return _ParentNode; }
}
///
/// Sets the node collection belongs to.
///
/// ColumnHeader that is parent of this collection.
internal void SetParentNode(Node parent)
{
_ParentNode = parent;
}
internal AdvTree Parent
{
get { return _Parent; }
set { _Parent = value; }
}
///
/// Adds new object to the collection.
///
/// Object to add.
/// Index of newly added object.
public int Add(ColumnHeader ch)
{
return List.Add(ch);
}
///
/// Returns reference to the object in collection based on it's index.
///
public ColumnHeader this[int index]
{
get { return (ColumnHeader)(List[index]); }
set { List[index] = value; }
}
///
/// Returns reference to the object in collection based on it's name.
///
public ColumnHeader this[string name]
{
get
{
int index = IndexOf(name);
if (index == -1) return null;
return this[index];
}
set { this[IndexOf(name)] = value; }
}
///
/// Inserts new object into the collection.
///
/// Position of the object.
/// Object to insert.
public void Insert(int index, ColumnHeader value)
{
List.Insert(index, value);
}
///
/// Returns index of the object inside of the collection.
///
/// Reference to the object.
/// Index of the object.
public int IndexOf(ColumnHeader value)
{
return List.IndexOf(value);
}
///
/// Returns index of the object inside of the collection.
///
/// Name of column to return index for.
/// Index of the column or -1 if column not found.
public int IndexOf(string name)
{
for (int i = 0; i < this.List.Count; i++)
{
if (this[i].Name == name) return i;
}
return -1;
}
///
/// Returns index of the object inside of the collection based on column DataFieldName.
///
/// DataFieldName of column to return index for.
/// Index of the column or -1 if column not found.
public int IndexOfDataField(string dataFieldName)
{
dataFieldName = dataFieldName.ToLower();
for (int i = 0; i < this.List.Count; i++)
{
if (this[i].DataFieldName.ToLower() == dataFieldName) return i;
}
return -1;
}
///
/// Returns index of the object inside of the collection based on column DataFieldName.
///
/// DataFieldName of column to return index for.
/// Index of the column or -1 if column not found.
internal int IndexOfField(string fieldName)
{
fieldName = fieldName.ToLower();
for (int i = 0; i < this.List.Count; i++)
{
ColumnHeader header = this[i];
if (header.Tag is BindingMemberInfo && ((BindingMemberInfo)header.Tag).BindingField.ToLower() == fieldName)
return i;
if (header.DataFieldName.ToLower() == fieldName) return i;
if (header.Name == fieldName) return i;
}
return -1;
}
///
/// Returns whether collection contains specified object.
///
/// Object to look for.
/// true if object is part of the collection, otherwise false.
public bool Contains(ColumnHeader value)
{
return List.Contains(value);
}
protected override void OnSet(int index, object oldValue, object newValue)
{
if (oldValue is ColumnHeader)
{
ColumnHeader header = (ColumnHeader)oldValue;
if (header.SortDirection != eSortDirection.None) IsSorted = false;
}
if (newValue is ColumnHeader)
{
ColumnHeader header = (ColumnHeader)newValue;
if (header.SortDirection != eSortDirection.None) IsSorted = true;
}
base.OnSet(index, oldValue, newValue);
}
///
/// Removes specified object from the collection.
///
///
public void Remove(ColumnHeader value)
{
List.Remove(value);
}
protected override void OnRemoveComplete(int index, object value)
{
if (value is ColumnHeader)
{
ColumnHeader header = (ColumnHeader)value;
if (header.SortDirection != eSortDirection.None) IsSorted = false;
header.HeaderSizeChanged -= new EventHandler(this.HeaderSizeChanged);
header.SortCells -= new SortCellsEventHandler(SortCellsHandler);
header.MouseDown -= new System.Windows.Forms.MouseEventHandler(ColumnMouseDown);
header.MouseUp -= new System.Windows.Forms.MouseEventHandler(ColumnMouseUp);
header.Parent = null;
}
InvalidateDisplayIndexes();
UpdateTreeLayout();
base.OnRemoveComplete(index, value);
}
protected override void OnInsertComplete(int index, object value)
{
if (value is ColumnHeader)
{
((ColumnHeader)value).HeaderSizeChanged += new EventHandler(this.HeaderSizeChanged);
((ColumnHeader)value).SortCells += new SortCellsEventHandler(SortCellsHandler);
((ColumnHeader)value).MouseDown += new System.Windows.Forms.MouseEventHandler(ColumnMouseDown);
((ColumnHeader)value).MouseUp += new System.Windows.Forms.MouseEventHandler(ColumnMouseUp);
((ColumnHeader)value).Parent = this;
}
InvalidateDisplayIndexes();
UpdateTreeLayout();
base.OnInsertComplete(index, value);
}
[System.Reflection.Obfuscation(Exclude = true)]
private void ColumnMouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
AdvTree tree = GetTree();
if (tree != null)
tree.InvokeColumnHeaderMouseUp(sender, e);
}
[System.Reflection.Obfuscation(Exclude = true)]
private void ColumnMouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
AdvTree tree = GetTree();
if (tree != null)
tree.InvokeColumnHeaderMouseDown(sender, e);
}
private AdvTree GetTree()
{
AdvTree tree = _Parent;
if (tree == null && _ParentNode != null)
tree = _ParentNode.TreeControl;
return tree;
}
///
/// Occurs before the cells are sorted.
///
[Description("Occurs before the cells are sorted.")]
public event SortCellsEventHandler SortCells;
protected virtual void OnSortCells(SortEventArgs e)
{
if (SortCells != null)
SortCells(this, e);
}
private void SortCellsHandler(object sender, SortEventArgs e)
{
ColumnHeader ch = (ColumnHeader)sender;
int i = this.IndexOf(ch);
IComparer comparer = null;
if (e.ReverseSort)
{
if (ch.SortComparerReverse != null)
comparer = ch.SortComparerReverse;
else
comparer = new NodeComparerReverse(i);
}
else
{
if (ch.SortComparer != null)
comparer = ch.SortComparer;
else
comparer = new NodeComparer(i);
}
if (e.Comparer == null)
e.Comparer = comparer;
else
comparer = e.Comparer;
OnSortCells(e);
if (e.Cancel)
return;
if (_Parent != null)
{
_Parent.Nodes.Sort(comparer);
}
else if (_ParentNode != null)
_ParentNode.Nodes.Sort(comparer);
}
private bool _UpdatingSortDirection = false;
///
/// Called when SortDirection property on column header is set to value other than None.
///
/// Ref to column header
internal void SortDirectionUpdated(ColumnHeader header)
{
if (_UpdatingSortDirection) return;
_UpdatingSortDirection = true;
try
{
if (header.SortDirection == eSortDirection.None)
{
IsSorted = false;
return;
}
IsSorted = true;
foreach (ColumnHeader col in this.List)
{
if (col != header && col.SortDirection != eSortDirection.None)
col.SortDirection = eSortDirection.None;
}
}
finally
{
_UpdatingSortDirection = false;
}
}
private bool _IsSorted;
///
/// Gets whether a column that is part of this collection has SortDirection set.
///
public bool IsSorted
{
get { return _IsSorted; }
internal set { _IsSorted = value; }
}
internal void UpdateSort()
{
if (!_IsSorted) return;
foreach (ColumnHeader header in this.List)
{
if (header.SortDirection != eSortDirection.None)
{
header.Sort(header.SortDirection == eSortDirection.Descending);
break;
}
}
}
private void UpdateTreeLayout()
{
if (_Parent != null)
{
_Parent.InvalidateNodesSize();
_Parent.Invalidate();
if (_Parent.Nodes.Count == 0)
_Parent.RecalcLayout();
else
_Parent.SetPendingLayout();
}
else if (_ParentNode != null)
{
AdvTree tree = _ParentNode.TreeControl;
if (tree != null)
{
tree.InvalidateNodeSize(_ParentNode);
tree.Invalidate();
}
}
}
private void HeaderSizeChanged(object sender, EventArgs e)
{
UpdateTreeLayout();
}
///
/// Copies collection into the specified array.
///
/// Array to copy collection to.
/// Starting index.
public void CopyTo(ColumnHeader[] array, int index)
{
List.CopyTo(array, index);
}
///
/// Copies contained items to the ColumnHeader array.
///
/// Array to copy to.
internal void CopyTo(ColumnHeader[] array)
{
List.CopyTo(array, 0);
}
protected override void OnClear()
{
foreach (ColumnHeader item in this)
{
item.HeaderSizeChanged -= new EventHandler(this.HeaderSizeChanged);
item.SortCells -= new SortCellsEventHandler(SortCellsHandler);
item.MouseDown -= new System.Windows.Forms.MouseEventHandler(ColumnMouseDown);
item.MouseUp -= new System.Windows.Forms.MouseEventHandler(ColumnMouseUp);
item.Parent = null;
}
IsSorted = false;
base.OnClear();
}
///
/// A map of display index (key) to index in the column collection (value). Used to quickly find a column from its display index.
///
internal List DisplayIndexMap
{
get
{
if (!_IsDisplayIndexValid)
{
UpdateDisplayIndexMap();
}
return _DisplayIndexMap;
}
}
///
/// Gets the display index for specified column.
///
/// Column that is part f ColumnHeaderCollection
/// Display index or -1 column is not part of this collection.
public int GetDisplayIndex(ColumnHeader column)
{
int index = this.IndexOf(column);
UpdateDisplayIndexMap();
for (int i = 0; i < _DisplayIndexMap.Count; i++)
{
if (_DisplayIndexMap[i] == index) return i;
}
return -1;
}
///
/// Returns the column that is displayed at specified display index..
///
/// 0 based display index.
/// ColumnHeader
public ColumnHeader ColumnAtDisplayIndex(int displayIndex)
{
UpdateDisplayIndexMap();
return this[_DisplayIndexMap[displayIndex]];
}
private List _DisplayIndexMap = new List();
private bool _IsDisplayIndexValid = false;
private void UpdateDisplayIndexMap()
{
if (_IsDisplayIndexValid) return;
_IsDisplayIndexValid = true;
_DisplayIndexMap.Clear();
List workingMap = new List();
bool isAllDefault = true;
for (int i = 0; i < Count; i++)
{
int displayIndex = this[i].DisplayIndex;
if (displayIndex != -1) isAllDefault = false;
workingMap.Add(new IndexToDisplayIndex(i, displayIndex));
}
if (!isAllDefault)
workingMap.Sort(new DisplayIndexComparer());
foreach (IndexToDisplayIndex item in workingMap)
{
_DisplayIndexMap.Add(item.Index);
}
}
///
/// Gets reference to last visible column or null if there is no last visible column.
///
public DevComponents.AdvTree.ColumnHeader LastVisibleColumn
{
get
{
List displayMap = DisplayIndexMap;
for (int i = displayMap.Count - 1; i >=0; i--)
{
if (this[displayMap[i]].Visible) return this[displayMap[i]];
}
return null;
}
}
///
/// Gets reference to first visible column or null if there is no first visible column.
///
public DevComponents.AdvTree.ColumnHeader FirstVisibleColumn
{
get
{
List displayMap = DisplayIndexMap;
for (int i = 0; i < displayMap.Count; i++)
{
if (this[displayMap[i]].Visible) return this[displayMap[i]];
}
return null;
}
}
#region IndexToDisplayIndex Class
private class IndexToDisplayIndex
{
public int Index = -1;
public int DisplayIndex = -1;
///
/// Initializes a new instance of the IndexToDisplayIndex class.
///
///
///
public IndexToDisplayIndex(int index, int displayIndex)
{
Index = index;
DisplayIndex = displayIndex;
}
}
#endregion
#region DisplayIndexComparer
private class DisplayIndexComparer : IComparer
{
#region IComparer Members
public int Compare(IndexToDisplayIndex x, IndexToDisplayIndex y)
{
if (x.DisplayIndex == y.DisplayIndex)
{
return x.Index - y.Index;
}
else
{
return x.DisplayIndex - y.DisplayIndex;
}
}
#endregion
}
#endregion
internal void DisplayIndexChanged(ColumnHeader column, int newDisplayIndex, int oldDisplayIndex)
{
InvalidateDisplayIndexes();
if (_UpdatingDisplayIndexes) return;
if (_Parent != null && !_Parent.IsUpdateSuspended)
UpdateTreeLayout();
else if (_ParentNode != null && _ParentNode.TreeControl != null && !_ParentNode.TreeControl.IsUpdateSuspended)
UpdateTreeLayout();
}
///
/// Invalidates the display indexes and causes them to be re-evaluated on next layout.
///
public void InvalidateDisplayIndexes()
{
_IsDisplayIndexValid = false;
}
#endregion
private Rectangle _Bounds = Rectangle.Empty;
internal void SetBounds(System.Drawing.Rectangle totalBounds)
{
_Bounds = totalBounds;
}
///
/// Gets the column header rendering bounds.
///
[Browsable(false)]
public Rectangle Bounds
{
get { return _Bounds; }
}
internal bool UsesRelativeSize = false;
private bool _UpdatingDisplayIndexes = false;
internal bool UpdatingDisplayIndexes
{
get { return _UpdatingDisplayIndexes; }
set { _UpdatingDisplayIndexes = value; }
}
}
}